﻿Imports System.Collections.Generic
Imports System.Drawing
Imports System.Data
Imports System.Linq
Imports System.IO
Imports System.ComponentModel
Imports WindowsHookLib
Imports System.Windows.Forms
Imports WindowsInput
Imports WindowsInput.Native
Imports System.Runtime.InteropServices
Imports System.Drawing.Imaging
Imports WebEye.Controls.WinForms.WebCameraControl
Imports System.Text.RegularExpressions

Imports Logger
'Imports InputManager

'Catch ex As Exception
'    _db.echo(ex.Message, True)
'    _db.echo(ex.StackTrace, True)
'End Try

Public Class MainProcess


    'Window Minimise
    Const SW_HIDE As Integer = 0
    Const SW_RESTORE As Integer = 1
    Const SW_MINIMIZE As Integer = 2
    Const SW_MAXIMIZE As Integer = 3


#Region "Properites"
    Private _db As DebugConsole
    Public Property DebugConsole() As DebugConsole
        Get
            Return _db
        End Get
        Set(ByVal value As DebugConsole)
            _db = value
        End Set
    End Property

    Private _log As Logger
    Public Property Log() As Logger
        Get
            Return _log
        End Get
        Set(ByVal value As Logger)
            _log = value
        End Set
    End Property

    Private _ds As DataSet
    Public Property DataSet() As DataSet
        Get
            Return _ds
        End Get
        Set(ByVal value As DataSet)
            _ds = value
        End Set
    End Property

    Private _BootCmd As Boolean
    Public Property FullBoot() As Boolean
        Get
            Return _BootCmd
        End Get
        Set(ByVal value As Boolean)
            _BootCmd = value
        End Set
    End Property

    Private _LeaveMounted As Boolean
    Public Property LeaveMounted() As Boolean
        Get
            Return _LeaveMounted
        End Get
        Set(ByVal value As Boolean)
            _LeaveMounted = value
        End Set
    End Property

    Private _geEmuID As Int32
    Public Property GEEmuID() As Int32
        Get
            Return _geEmuID
        End Get
        Set(ByVal value As Int32)
            _geEmuID = value
        End Set
    End Property

    Private _romName As String
    Public Property RomName() As String
        Get
            Return _romName
        End Get
        Set(ByVal value As String)
            _romName = value
        End Set
    End Property

    Private _gameBio As String
    Public Property GameBio() As String
        Get
            Return _gameBio
        End Get
        Set(ByVal value As String)
            _gameBio = value
        End Set
    End Property


    Private _gameInfo As GameEx.Plugin.Game_Info
    Public Property GameInfo() As GameEx.Plugin.Game_Info
        Get
            Return _gameInfo
        End Get
        Set(ByVal value As GameEx.Plugin.Game_Info)
            _gameInfo = value
        End Set
    End Property

    Private _cmdLine As String = ""
    Public ReadOnly Property CmdLine() As String
        Get
            Return _cmdLine
        End Get
    End Property

    Private _cmdexe As String
    Public Property CmdExe() As String
        Get
            Return _cmdexe
        End Get
        Set(ByVal value As String)
            _cmdexe = value
        End Set
    End Property

    Private _cmdparams As String
    Public Property CmdParams() As String
        Get
            Return _cmdparams
        End Get
        Set(ByVal value As String)
            _cmdparams = value
        End Set
    End Property

    Private _sysSetupID As Integer
    Public ReadOnly Property SystemSetupID() As Integer
        Get
            Return _sysSetupID
        End Get
    End Property

    Private _userEmuID As Integer
    Public ReadOnly Property UserEmuID() As Integer
        Get
            Return _userEmuID
        End Get
    End Property

    Private _tokens As Dictionary(Of String, String)
    Public ReadOnly Property Tokens() As Dictionary(Of String, String)
        Get
            Return _tokens
        End Get
    End Property

    Private _PassedGameID As Integer
    Public Property PassGameID() As Integer
        Get
            Return _PassedGameID
        End Get
        Set(ByVal value As Integer)
            _PassedGameID = value
        End Set
    End Property

    Private _UseDefaultGame As Boolean = True
    Public Property UseDefaultGame() As Boolean
        Get
            Return _UseDefaultGame
        End Get
        Set(ByVal value As Boolean)
            _UseDefaultGame = value
        End Set
    End Property

    Private _skipclose As Boolean
    Public Property SkipClose() As Boolean
        Get
            Return _skipclose
        End Get
        Set(ByVal value As Boolean)
            _skipclose = value
        End Set
    End Property
#End Region


    'OTHER VARS:

    'TOKENS
    Private _tokensJig As New Dictionary(Of String, String) From {{"[ROMPATH]", ""}, {"[ROMNAME]", ""},
                                                                    {"[PATHUSED]", ""}, {"[ROMBARE]", ""},
                                                                    {"[GECMDLINE]", "[GEMCMDLINE]"},
                                                                    {"[ROMUSED]", ""}, {"[LAUNCHFILE]", ""},
                                                                    {"[QLAUNCHROOT]", ""}, {"[QLAUNCHGAME]", ""},
                                                                    {"[VDRIVELTR]", ""}, {"[VDRIVETYPE]", ""},
                                                                    {"[GESYSTEM]", ""}, {"[GEMSYSTEM]", ""},
                                                                    {"[GEEMULATOR]", ""}, {"[GEMEMULATOR]", ""},
                                                                    {"[GEDATABASE]", ""}, {"[EMUROOT]", ""},
                                                                    {"[GEEMUSTART]", ""}, {"[GEEMUTITLE]", ""},
                                                                    {"[GEGAMENAME]", ""}, {"[GEMGAMENAME]", ""},
                                                                    {"[PRIORITYGAMENAME]", ""},
                                                                    {"[CATAGORY]", ""}, {"[YEAR]", ""},
                                                                    {"[DEVELOPER]", ""}, {"[DESCRIPTION]", ""},
                                                                    {"[SNAPPATH]", ""}, {"[TITLEPATH]", ""},
                                                                    {"[SNAPIMG]", ""}, {"[TITLEIMG]", ""},
                                                                    {"[GEMCUSTOM1]", ""}, {"[GEMCUSTOM2]", ""}}

    'EMU BOOT SPECIFY:
    Public SpecdEmuSetupID As Integer = -1
    Public UseSpecificEmu As Boolean = False

    Public RomPath As String = Nothing
    Public RomUsed As String = Nothing
    Public Launchfile As String = Nothing
    Public QLaunchRoot As String = Nothing
    Public QLaunchGame As String = Nothing
    Public VDriveLetter As String = Nothing
    Public VDriveType As String = Nothing

    Public GEEmudbID As Integer
    Public GameID As Integer = Nothing
    Public GameQLDir As String = Nothing

    Public SkipMount As Boolean = False

    Public msg As New ProcMessage
    Public UZipExit As Integer
    Public DToolsReturn As Integer

    Public Game As DataRow = Nothing
    Public SysSetup As DataRow = Nothing
    Public EmuSetup As DataRow = Nothing
    Public VDrive As DataRow = Nothing

    Private Unzip As BackgroundWorker = New BackgroundWorker
    Private UnEcm As BackgroundWorker = New BackgroundWorker
    Private UnApe As BackgroundWorker = New BackgroundWorker
    Private Mount As BackgroundWorker = New BackgroundWorker
    Private UnMount As BackgroundWorker = New BackgroundWorker
    Private SupportApp As BackgroundWorker = New BackgroundWorker
    Private CopyBG As BackgroundWorker = New BackgroundWorker

    Public Class WorkerArgs
        Public Arg1 As Object
        Public Arg2 As Object = False
        Public Arg3 As Object = False
    End Class

    'CAM SNAPS
    Private CamSnap As BackgroundWorker = New BackgroundWorker
    Public Cams As New List(Of WebEye.Controls.WinForms.WebCameraControl.WebCameraId)
    Public WCFeed As New WebEye.Controls.WinForms.WebCameraControl.WebCameraControl




    Public SAppsDT As New DataTable

    Public ProcList As New List(Of Process)
    Dim myprocess As New Process
    Public finalsize As Long = 0

    ' KEYBOARD HOOKS ----------------------------
    'Class level declarations
    Dim WithEvents kHook As New KeyboardHook
    Dim WithEvents mHook As New MouseHook
    Dim WithEvents cHook As New ClipboardHook
    Public KeyLookup As New List(Of Integer)
    Public GKeyMap As New KeyMap
    Public KeysDC As New Dictionary(Of Integer, List(Of Object))
    Public KeysTest As New Dictionary(Of Integer, Integer) ' int = primary keymapping for key. Minus values indicate alt maps for the key

    'Allowed control handle list
    Dim alowedList As New List(Of IntPtr)
    'Output:
    Dim KeyOut As New WindowsInput.InputSimulator
    Public SendingKey As Boolean = False
    'HOTKEYS
    ' Dim WithEvents Hotkeys As NHotkey.WindowsForms.HotkeyManager

    Public WithEvents unziptimer As New Timer
    Public WithEvents CopyTimer As New Timer


    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function ShowWindowAsync(ByVal hwnd As IntPtr, ByVal nCmdShow As Integer) As Boolean
    End Function

    Public Sub MinimiseGameEx()
        _db.echo("Minimise GameEx")
        Try
            Dim GEProc As Process() = Process.GetProcessesByName("GameEx")
            'For Each proc As Process In GEProc
            '    _db.echo("Win: " & proc.MainWindowTitle)
            '    Dim hWnd As Integer = CType(proc.MainWindowHandle, Integer)
            '    ShowWindowAsync(hWnd, SW_MINIMIZE)
            'Next

            Dim hWnd As IntPtr = FindWindow("GameEx", Nothing)
            ShowWindowAsync(hWnd, SW_HIDE)

        Catch ex As Exception
            _db.echo(ex.Message, True)
            _db.echo(ex.StackTrace, True)
        End Try
    End Sub

    Public Sub SendAltEnter()
        KeyOut.Keyboard.ModifiedKeyStroke(VirtualKeyCode.MENU, VirtualKeyCode.RETURN)
    End Sub

    Public Sub SendWinD()
        KeyOut.Keyboard.ModifiedKeyStroke(VirtualKeyCode.RWIN, VirtualKeyCode.VK_D)
        KeyOut.Keyboard.ModifiedKeyStroke(VirtualKeyCode.RWIN, VirtualKeyCode.VK_M)
    End Sub


    Private Sub SetupDTs()

        With SAppsDT
            .TableName = "SAppsDT"
            .Columns.Add("SSID", GetType(Integer))
            .Columns.Add("Timing", GetType(String))
            .Columns.Add("SpecificParams", GetType(String))
            .Columns.Add("Name", GetType(String))
            .Columns.Add("Exe", GetType(String))
            .Columns.Add("DefaultParams", GetType(String))
            .Columns.Add("QuitWithGemvoy", GetType(Boolean))
            .Columns.Add("WaitToFinish", GetType(Boolean))
            .Columns.Add("WaitForIdle", GetType(Boolean))
            .Columns.Add("AppVisibility", GetType(String))
        End With

    End Sub

    Public Sub TEST()

        msg.Show()

        ' unziptimer.Enabled = True
        unziptimer.Interval = 2000
        CopyTimer.Interval = 2000

        GameQLDir = "C:\tests"


        Dim finalsize As Integer = UnzippedSize("I:\EmuTests\roms\Playstation\MIxedSet\Wipeout XL.7z")
        _db.echo("Final Size: " & finalsize)

        'MsgBox(finalsize)
        'msg.ProgressBar1.Maximum = finalsize
        'msg.ProgressBar1.Minimum = 0
        'msg.ProgressBar1.Value = 1

        Dim SApp As New Process
        With SApp.StartInfo
            .FileName = "C:\Program Files\7-Zip\7zG.exe"
            .Arguments = "e ""I:\EmuTests\roms\Playstation\MIxedSet\Wipeout XL.7z"" -oc:\tests"
            .WindowStyle = ProcessWindowStyle.Normal
        End With

        unziptimer.Enabled = True
        unziptimer.Start()

        Unzip.RunWorkerAsync("I:\EmuTests\roms\Playstation\MIxedSet")

        While Unzip.IsBusy
            Windows.Forms.Application.DoEvents()
        End While

        'SApp.Start()
        'SApp.WaitForExit()
        unziptimer.Stop()

    End Sub

    Private Sub UNzipTTick() Handles unziptimer.Tick
        '_db.echo("Timer tick..")
        Dim pressize As Long = GetFolderSize(GameQLDir)
        If pressize < finalsize Then
            _db.echo("Timer Tick. New Size: " & pressize)
            'msg.ProgressBar1.Value = pressize
            msg.Msg2LB.Text = Math.Round(pressize / 1048576) & "M / " & Math.Round(finalsize / 1048576) & "M"
        End If

    End Sub



    Function GetFolderSize(ByVal DirPath As String, _
         Optional IncludeSubFolders As Boolean = True) As Long

        Dim lngDirSize As Long
        Dim objFileInfo As FileInfo
        Dim objDir As DirectoryInfo = New DirectoryInfo(DirPath)
        Dim objSubFolder As DirectoryInfo

        Try

            'add length of each file
            For Each objFileInfo In objDir.GetFiles()
                lngDirSize += objFileInfo.Length
            Next

            'call recursively to get sub folders
            'if you don't want this set optional
            'parameter to false 
            If IncludeSubFolders Then
                For Each objSubFolder In objDir.GetDirectories()
                    lngDirSize += GetFolderSize(objSubFolder.FullName)
                Next
            End If

        Catch Ex As Exception
            _db.echo("Exception thrown in get folder size")
        End Try
        Return lngDirSize
    End Function


    Private Function UnzippedSize(ZipFile As String) As Long
        _log.echo("> Get unzipped size routine. Recieved: " & ZipFile)
        _log.echo("7z cmd used: ")
        _log.echo("""" & GEmvoy.Setts.ZipExe & """ l """ & ZipFile & """")
        Try
            Dim SApp As New Process
            With SApp.StartInfo
                .UseShellExecute = False
                .FileName = GEmvoy.Setts.ZipExe
                .Arguments = " l """ & ZipFile & """"
                .WindowStyle = ProcessWindowStyle.Normal
                .RedirectStandardOutput = True
            End With

            If Not File.Exists(SApp.StartInfo.FileName) Then
                Return 0
            End If

            SApp.Start()

            Dim output As String = SApp.StandardOutput.ReadToEnd()
            SApp.WaitForExit()

            _db.echo("")
            _db.echo("StdOut:")
            _db.echo(output)
            _db.echo("")

            Dim TextLines() As String = output.Split(Environment.NewLine.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries)
            Dim FinalOut As String = Nothing
            Dim SeparatorCount = 0
            For i As Int32 = 0 To TextLines.Count - 1
                _db.echo("Line: " & TextLines(i))
                If TextLines(i).Split(" ")(0) = "-------------------" Then
                    _db.echo("Spearator found. Count: " & SeparatorCount)
                    SeparatorCount += 1
                End If
                If SeparatorCount = 2 Then
                    FinalOut = TextLines(i + 1)
                    Exit For
                End If
            Next

            _db.echo("Finalout from loop: " & FinalOut)

            _db.echo("Last Line StdOut: " & FinalOut)
            FinalOut = FinalOut.Remove(0, 19)
            _db.echo("Finalout,remove: " & FinalOut)
            FinalOut = FinalOut.Trim
            _db.echo("Finalout,trim: " & FinalOut)
            FinalOut = FinalOut.Split(" ")(0)
            _db.echo("Finalout,split: " & FinalOut)

            If IsNumeric(FinalOut) Then
                _log.echo("Value retrieved for folder size: " & FinalOut)
                Return CLng(FinalOut)
            Else
                _log.echo("ERROR: Value could not be converted to int - throwing error")
                Return -1
            End If

        Catch ex As Exception
            _log.echo("ERROR: Could not complete get zip size")
            _log.echo(ex.Message, True)
            _log.echo(ex.StackTrace, True)

        End Try

        Return -1

    End Function


    Public Sub Initialise()

        '  Hotkeys.AddOrReplace("Test1", Keys.A, TestHotKey)

        'time between folder size checks on unzip routine + progress bar:
        unziptimer.Interval = 1000
        CopyTimer.Interval = 1000

        _db.TextColor = Color.Yellow
        _db.echo("", False, "starting main process - intialising")
        _db.echo("Receved vars:")
        _db.echo("GEEmuID: " & _geEmuID.ToString)
        _db.echo("RomFile: " & _romName)

        SetupDTs()

        _tokens = _tokensJig

        CopyBG.WorkerReportsProgress = True
        CopyBG.WorkerSupportsCancellation = False
        RemoveHandler CopyBG.DoWork, AddressOf CopyBG_dowork
        AddHandler CopyBG.DoWork, AddressOf CopyBG_dowork

        Unzip.WorkerReportsProgress = True
        Unzip.WorkerSupportsCancellation = False
        RemoveHandler Unzip.DoWork, AddressOf UnZip_dowork
        AddHandler Unzip.DoWork, AddressOf UnZip_dowork

        Unzip.WorkerReportsProgress = True
        Unzip.WorkerSupportsCancellation = False
        RemoveHandler UnEcm.DoWork, AddressOf UnEcm_dowork
        AddHandler UnEcm.DoWork, AddressOf UnEcm_dowork

        UnApe.WorkerReportsProgress = True
        UnApe.WorkerSupportsCancellation = False
        RemoveHandler UnApe.DoWork, AddressOf UnAPE_dowork
        AddHandler UnApe.DoWork, AddressOf UnAPE_dowork

        Mount.WorkerReportsProgress = True
        Mount.WorkerSupportsCancellation = False
        RemoveHandler Mount.DoWork, AddressOf Mount_dowork
        AddHandler Mount.DoWork, AddressOf Mount_dowork

        UnMount.WorkerReportsProgress = True
        UnMount.WorkerSupportsCancellation = False
        RemoveHandler UnMount.DoWork, AddressOf UnMount_dowork
        AddHandler UnMount.DoWork, AddressOf UnMount_dowork

        SupportApp.WorkerReportsProgress = True
        SupportApp.WorkerSupportsCancellation = False
        RemoveHandler SupportApp.DoWork, AddressOf SupportApp_dowork
        AddHandler SupportApp.DoWork, AddressOf SupportApp_dowork

        CamSnap.WorkerReportsProgress = True
        CamSnap.WorkerSupportsCancellation = True
        RemoveHandler CamSnap.DoWork, AddressOf StartCamSnap
        AddHandler CamSnap.DoWork, AddressOf StartCamSnap

        'get cam list:
        For Each cam As WebEye.Controls.WinForms.WebCameraControl.WebCameraId In WCFeed.GetVideoCaptureDevices
            Cams.Add(cam)
        Next

    End Sub

    Public Sub AfterGameQuit()

        Try
            msg = New ProcMessage()
            _log.echo("====================================")
            _log.echo("", "GAME CLOSED ROUTINES")

            CamSnap.CancelAsync()

            msg.Show()
            msg.ChangeMsg("Closing down game...", 1)
            ' Stop keyhooks
            _log.echo("Removing Keyhook")
            Try
                kHook.RemoveHook()
                _log.echo("Keyhook Removed")
            Catch
                _log.err("Keyhook remove error")
            End Try

            ' SUPPORT APPS
            ' BOOT ANY AFTER APPS
            _log.echo("Booting any 'after' support apps")
            For Each approw As DataRow In SAppsDT.Rows
                _db.echo("approw: " & approw("Name"))
                _db.echo("Wait: " & approw("WaitToFinish"))
                If approw("Timing") = "After" Then
                    Dim finalparam As String = ReplaceTokens(approw("DefaultParams"))
                    If Not (String.IsNullOrEmpty(approw("SpecificParams").ToString())) Then finalparam = ReplaceTokens(approw("SpecificParams"))
                    Dim SApp As New ProcessStartInfo
                    With SApp
                        .FileName = approw("Exe")
                        .Arguments = finalparam
                        .WindowStyle = ReturnWindowStyle(approw("AppVisibility"))
                    End With

                    If approw("WaitToFinish") = True Then
                        _log.echo("Wait to finish on support app...")
                        _log.echo("Started 'wait to finish' app: " & approw("Name"))
                        _log.echo("Window: " & approw("AppVisibility"))
                        msg.ChangeMsg("Awaiting 'Wait to finish' App end...", 2)
                        SupportApp.RunWorkerAsync(SApp)
                        While SupportApp.IsBusy
                            Windows.Forms.Application.DoEvents()
                        End While
                    Else
                        msg.ChangeMsg("Launching App...", 2)
                        _log.echo("Started app: " & approw("Name"))
                        _log.echo("Window: " & approw("AppVisibility"))
                        'myprocess = Process.Start(SApp)
                        ' myprocess.Refresh()
                        ProcList.Add(Process.Start(SApp))
                        ' Process.Start(SApp)
                    End If
                End If
            Next

            msg.ChangeMsg("Saving Emulator settings..", 2)

            'SAVE EMU SETTS + LOAD DEFAULT
            _log.echo("Saving/Loading default emulator settings...")

            Try
                _log.echo("Use Settings Algo?: " & NotNull(EmuSetup("UseSettsAlgo"), "null"))
                If NotNull(EmuSetup("UseSettsAlgo"), False) = True Then
                    _log.echo("Use Emulator Settings Algorithm set to TRUE. Saving Emulator Settings...")
                    SaveSettings(CInt(SysSetup("ID")), CInt(EmuSetup("ID")), CInt(Game("ID")),
                                 False, False, GEmvoy.Setts.SuppSettsAudio)
                    'Load Default Prof back in:
                    _log.echo("Now restoring Default Emulator Settings...")
                    LoadSettings(CInt(SysSetup("ID")), CInt(EmuSetup("ID")), CInt(Game("ID")),
                                 True, False, True, True)
                Else
                    _log.echo("Use Emulator Settings Algorithm set to FALSE. Not running Emu Settings routines...")
                End If
            Catch ex As Exception
                _log.echo("Error Saving/Loading Emu settings:")
                _log.echo(ex.Message, True)
                _log.echo(ex.StackTrace, True)
            End Try

            'QUIT APPS
            _log.echo("Quitting support apps")

            msg.ChangeMsg("Closing support apps..", 2)
            For Each proc As Process In ProcList
                If proc.HasExited = False Then
                    _log.echo("Closing Process: " & proc.ProcessName)
                    proc.CloseMainWindow()
                End If
                'If proc.HasExited = False Then
                '    proc.Kill()
                'End If
            Next


            'UNMOUNT
            Try
                _log.echo("Doing any unmount.")
                If _LeaveMounted = False Then
                    If EmuSetup("ImageMount") = True And Game("DisableMount") = False Then
                        msg.ChangeMsg("Unmounting Image", 2)
                        UnMount.RunWorkerAsync()
                        While UnMount.IsBusy
                            Windows.Forms.Application.DoEvents()
                        End While
                    End If
                Else
                    _log.echo("Leave Mount selected in config....")
                End If
            Catch ex As Exception
                _log.echo("Error Unmounting:")
                _log.echo(ex.Message, True)
                _log.echo(ex.StackTrace, True)
            End Try


            'PROCESS QUICKLAUNCH FOLDER
            _log.echo("Process Quicklaunch folder.")
            _log.echo("QLaunch Folder: " & _tokens("[QLAUNCHGAME]"))

            Dim QLFinal As String = Nothing
            If Game("QuickLaunchPrompt") = "As per System Setup" Then
                QLFinal = SysSetup("QuicklaunchPrompt")
            Else
                QLFinal = Game("QuickLaunchPrompt")
            End If

            _log.echo("Final QL action: " & QLFinal)


            If SysSetup("UseQuicklaunch") = True Then

                Select Case QLFinal

                    Case "Ask"
                        Dim picker As New QLPicker

                        With picker
                            .QLKeepAlwaysKey = GEmvoy.Setts.QLKeepAlwaysKey
                            .QLKeepOnceKey = GEmvoy.Setts.QLKeepOnceKey
                            .QLDelAlwaysKey = GEmvoy.Setts.QLDelAlwaysKey
                            .QLDelOnceKey = GEmvoy.Setts.QLDelOnceKey
                            .QLSelectKey = GEmvoy.Setts.QLSelectKey
                        End With

                        msg.Hide()
                        picker.ShowDialog()
                        _log.echo("Action dialogue. User chose: " & picker.Picked)

                        Select Case picker.Picked
                            Case "DelAlways"
                                Directory.Delete(_tokens("[QLAUNCHGAME]"), True)
                                Game("QuickLaunchPrompt") = "Delete"
                            Case "DelOnce"
                                Directory.Delete(_tokens("[QLAUNCHGAME]"), True)
                            Case "KeepAlways"
                                Game("QuickLaunchPrompt") = "Keep"
                            Case "KeepOnce"
                                Game("QuickLaunchPrompt") = "Ask"
                        End Select

                        picker.Close()

                    Case "Delete"
                        Try
                            Directory.Delete(_tokens("[QLAUNCHGAME]"), True)
                            _log.echo("Defective Quicklaunch folder deleted.")
                        Catch
                            _log.echo("ERROR: Whilst deleting quickalunch folder - please check + delete manually if neccessary")
                        End Try

                    Case "Keep"
                        'do nutttin

                End Select

            End If

            msg.Close()

        Catch ex As Exception
            _db.echo(ex.Message, True)
            _db.echo(ex.StackTrace, True)
        End Try

        If _db.WindowState = FormWindowState.Minimized Then
            _db.WindowState = FormWindowState.Normal
        End If



        _log.echo("", "end of GAME CLOSED ROUTINES")
        _log.echo("0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0=0")
        _log.echo("")

    End Sub

    Public Sub ProcessInput()

        ' MsgBox("game start setts test: " & My.Settings.CamTest)

        Dim CleanFolderName As String = Nothing

        Dim TempFolder As String = My.Computer.FileSystem.SpecialDirectories.Temp & "\GEmvoyTemp"

        Dim UsingQL As Boolean = False
        Dim QLFilesExtant As Boolean = False
        Dim ImgMounted As Boolean = False

        Dim SysSetupID As Integer

        _log.echo("====================================")
        _log.echo("", "Starting Game Launch")
        _log.echo("Vars at runtime:")
        _log.echo("GameEx EmuID: " & GEEmuID)
        _log.echo("Romname: " & RomName)
        _log.echo("Passed GameID: " & PassGameID)
        _log.echo("Leave Mounted?: " & LeaveMounted)
        _log.echo("Use Default Game Profile?: " & UseDefaultGame)
        _log.echo("Use specified Emulator?: " & UseSpecificEmu)
        _log.echo("Specific EmuSetupID: " & SpecdEmuSetupID)
        _log.echo("----------------------------------")

        'minimize debug

        _db.WindowState = FormWindowState.Minimized

        _db.echo("", False, "process input")
        'Figure GEEmu database ID:
        Dim selrow() As DataRow = Nothing
        selrow = _ds.Tables("UserEmulators").Select("UserEmuGEID = '" & _geEmuID & "'")
        GEEmudbID = selrow(0).Item("ID")
        _tokens("[GEEMUSTART]") = selrow(0)("StartPageName")
        _tokens("[GEEMUTITLE]") = selrow(0)("TitleText")
        _tokens("[GEDATABASE]") = selrow(0)("Database")

        _log.echo("GameEx Emu(StartPageName): " & selrow(0)("StartPageName"))

        'discern SysSetupID from GEEmuID:
        For Each row As DataRow In _ds.Tables("SystemsSetups").Rows
            _db.echo("processing SysSetups row: " & row.Item("Name"))
            _db.echo(row.Item("UserEmuID") & ", " & _geEmuID)
            If row.Item("UserEmuID") = GEEmudbID Then
                _db.echo("SysSetups row found: " & row.Item("ID"))
                _sysSetupID = row.Item("ID")
            End If
        Next

        selrow = _ds.Tables("SystemsSetups").Select("ID = '" & _sysSetupID.ToString & "'")
        _db.echo(selrow(0).Item("Name"), False, "Output")
        ' MsgBox(selrow(0).Item("Name"))

        '==========================================================================================
        'VARS DEFINED AT THIS POINT:
        ' _sysSetupID:      SystemsSetups.ID (+prop)
        ' GEEmudbID:        UserEmulators.ID
        '==========================================================================================

        _log.echo("Associated GEmvoy System Setup: " & selrow(0)("Name"))

        'Test if Use Gemvoy for this System:
        If selrow(0).Item("UseGEmvoy") = False Then
            _cmdLine = ""     'Return blank command line
            _log.echo("Use Gemvoy set to FALSE for this System Setup - returning blank cmd line")
            _skipclose = True
            Return
        End If

        msg.ChangeMsg("Starting Game Launch...", 1)
        msg.ChangeMsg("", 2)
        'if setting = true then show procmessage
        msg.Show()
        msg.BringToFront()
        msg.TopMost = True

        SysSetupID = selrow(0).Item("ID")

        'Populate System tokens:
        _tokens("[ROMPATH]") = selrow(0)("RomsFolder")
        _tokens("[ROMNAME]") = _romName
        _tokens("[ROMBARE]") = Path.GetFileNameWithoutExtension(_romName)
        _tokens("[QLAUNCHROOT]") = selrow(0)("QuicklaunchRoot")
        _tokens("[GEMSYSTEM]") = selrow(0)("Name")

        Dim selrow2() As DataRow = _ds.Tables("SystemsList").Select("ID = '" & selrow(0).Item("SystemID") & "'")
        _tokens("[GESYSTEM]") = selrow2(0)("Name")

        msg.ChangeMsg("Checking if Game Profile already exists...", 1)

        'figure vars for passing to add new game if neccessary:
        _log.echo("Vars if adding new game: ")
        _log.echo("_sysSetupID: " & _sysSetupID)
        Dim emuid As Integer = CInt(_ds.Tables("SystemsSetups").Select("ID = " & _sysSetupID)(0).Item("DefEmuSetupID"))
        Dim pergamesetts As Boolean = CBool(_ds.Tables("EmuSetups").Select("ID = " & emuid)(0).Item("PerGameSetts"))
        Dim EmuDefSettsID As Integer = CInt(_ds.Tables("EmuSetups").Select("ID = " & emuid)(0).Item("EmuSettsProfileID"))

        _log.echo("Checking ROM for associated Game Profile...")
        'Test if Game Profile exists for this Rom:
        selrow = _ds.Tables("Games").Select("RomFile = '" & MakeSQLSafe(_romName) & "' AND SysSetupID = '" & SysSetupID & "'")
        GameID = -1

        'START CHANGES HERE FOR IN_MENU EMU CHOOSE
        If selrow.Length = 0 Then
            _log.echo("No Game Profile for the pased rom: " & _romName & ". Going to make new Game Profile.")
            msg.ChangeMsg("Making new Game Profile...", 2)
            Try
                GameID = AddGame(_sysSetupID, emuid, pergamesetts, EmuDefSettsID) '<-- here - easily missed! ' THIS'LL NEED CHANGING - DONE!
            Catch ex As Exception
                _db.echo(ex.Message, True)
                _db.echo(ex.StackTrace, True)
                msg.Close()
            End Try

        ElseIf selrow.Length = 1 Then
            _log.echo("Only 1 Game Profile for the pased rom: " & _romName & ". Testing whether Emu specified in GameEx launch.....")
            If UseSpecificEmu = True And selrow(0).Item("EmuSetupID") <> SpecdEmuSetupID And SpecdEmuSetupID <> -1 Then
                msg.ChangeMsg("Single Game Profile Found...", 2)
                _log.echo("Use specific emu set to true and EmuSetupID in single game profile does not match Specified Emu. Creating new game profile with spec'd Emu.")
                GameID = AddGame(_sysSetupID, emuid, pergamesetts, EmuDefSettsID)
            Else
                _log.echo("Either Use specific emu set to False, Spec'd emuID = -1 or spec'd Emu = this game's emu")
                GameID = selrow(0).Item("ID")  ' TEST: if matches spec'd emu then use, else new game
            End If
        Else
            _log.echo("More than 1 Game Profile for the pased rom: " & _romName & ". Finding the default one...")
            msg.ChangeMsg("Multiple Game Profiles Found...", 2)
            If _UseDefaultGame = False Then
                'This SUPERCEDES EMU SPECIFY TO ENSURE CONFIG RUN SPECIFIC GAME PROFILE WORKS
                _log.echo("Use Default Game set to FALSE (from config) - use Passed game ID")
                GameID = _PassedGameID ' << test this that emu is same as spec'd
            Else

                For Each row As DataRow In selrow
                    If row.Item("DefaultForGame") = True Then ' << again,test this that emu is same as spec'd
                        _db.echo("Found Default Game Profile")
                        If UseSpecificEmu = True And SpecdEmuSetupID <> -1 Then
                            _db.echo("Use Specified Emu set to true")
                            If row.Item("EmuSetupID") = SpecdEmuSetupID Then
                                _log.echo("Found Default Game Profile and matches Spec'd emu: " & row.Item("UniqueGameName"))
                                GameID = row.Item("ID")
                            End If
                        Else
                            _log.echo("Found Default Game Profile and Emu not spec'd" & row.Item("UniqueGameName"))
                            GameID = row.Item("ID")
                        End If
                    End If
                Next

                If GameID = -1 Then
                    'permutations:
                    'no default game defined
                    'default defined, but didn't match emu
                    _log.echo("Either no default game defined or one was but Emu specified and didn't match...")
                    Dim SpecEmuRow() As DataRow = _ds.Tables("Games").Select("RomFile = '" & MakeSQLSafe(_romName) & "' AND SysSetupID = '" & SysSetupID & "' AND EmuSetupID = '" & SpecdEmuSetupID & "'")
                    ' Dim SpecEmuRow() As DataRow = selrow.ToDataTable.Select("EmuSetupID = " & SpecdEmuSetupID)
                    If UseSpecificEmu = True And SpecdEmuSetupID <> -1 Then
                        _db.echo("Use Spec emu set to true and not use default")
                        If SpecEmuRow.Length = 0 Then
                            _db.echo("No Game Profiles matching Specified Emu. Make")
                            GameID = AddGame(_sysSetupID, emuid, pergamesetts, EmuDefSettsID)
                        Else
                            _db.echo("Game Profile matching Specified Emu exists. Use this.")
                            GameID = SpecEmuRow(0).Item("ID")
                        End If
                    Else
                        _db.echo("Use Spec emu set to false. Set game profile to the first one found. CHECK DEFAULT GAME PROFILE SET VIA CONFIG")
                        GameID = selrow(0).Item("ID")
                    End If
                End If
            End If
        End If

        _log.echo("Final Game ID: " & GameID)

        'Test GEGAmeName + update if rel
        selrow = _ds.Tables("Games").Select("ID = '" & GameID & "'")
        If selrow(0).Item("GEGameName") = "" And _gameInfo.GameName <> "" Then
            selrow(0).Item("GEGameName") = _gameInfo.GameName
            _log.echo("GEGameName was null in db and GE Game name exists. Updated with value: " & _gameInfo.GameName)
        End If



        '==========================================================================================
        'VARS DEFINED AT THIS POINT:
        ' GameID:        Games.ID
        '==========================================================================================

        'Load Game, Sys and Emu:

        Game = selrow(0)
        selrow = _ds.Tables("SystemsSetups").Select("ID = '" & Game("SysSetupID") & "'")
        SysSetup = selrow(0)
        selrow = _ds.Tables("EmuSetups").Select("ID = '" & Game("EmuSetupID") & "'")
        EmuSetup = selrow(0)

        _log.echo("Derived record sets:")
        _log.echo("Game: " & Game.Item("EditedGameName"))
        _log.echo("System: " & SysSetup("Name"))
        _log.echo("Emulator: " & EmuSetup("Name") & vbCr)

        _log.echo("Testing Emu exe: " & EmuSetup("Exe"))
        If Not (File.Exists(EmuSetup("Exe"))) Then
            _log.echo("Emulator exe does not exist - exiting as cannot proceed")
            msg.ChangeMsg("Error with Emulator EXE. Aborting...", 1)
            msg.Close()
            Return
        Else
            _log.echo("Emu exe exists")
        End If

        _log.echo("Populating Tokens - first round")

        'Populate other Tokens:
        selrow = _ds.Tables("EmulatorList").Select("ID = '" & EmuSetup("EmuID") & "'")
        _tokens("[GEEMULATOR]") = selrow(0)("Name")
        _tokens("[GEMEMULATOR]") = EmuSetup("Name")
        _tokens("[EMUROOT]") = Path.GetDirectoryName(EmuSetup("Exe"))
        _tokens("[VDRIVETYPE]") = EmuSetup("DriveType")
        _tokens("[VDRIVELTR]") = EmuSetup("DriveLetter")
        _tokens("[GEGAMENAME]") = NotNull(Game("GEGameName"), "")
        _tokens("[GEMGAMENAME]") = NotNull(Game("EditedGameName"), "")

        _tokens("[PRIORITYGAMENAME]") = _tokens("[GEMGAMENAME]")
        If _tokens("[GEGAMENAME]") <> "" Then
            _tokens("[PRIORITYGAMENAME]") = _tokens("[GEGAMENAME]")
        End If

        _tokens("[GEMCUSTOM1]") = NotNull(Game("Custom1"), "")
        _tokens("[GEMCUSTOM2]") = NotNull(Game("Custom2"), "")
        _tokens("[CATAGORY]") = NotNull(_gameInfo.GameData.Category, "")
        _tokens("[YEAR]") = NotNull(_gameInfo.GameData.Year, "")
        _tokens("[DEVELOPER]") = NotNull(_gameInfo.GameData.Developer, "")
        _tokens("[DESCRIPTION]") = NotNull(_gameBio, "")
        _tokens("[SNAPPATH]") = NotNull(_gameInfo.SnapPath, "")
        Try


            If _tokens("[SNAPPATH]") <> "" Then
                Dim paths() As String = IO.Directory.GetFiles(_gameInfo.SnapPath, _tokens("[ROMBARE]") & ".*")
                If paths.Length > 0 Then 'if at least one file is found do something
                    _tokens("[SNAPIMG]") = Path.GetFileName(paths(0))
                End If
            End If

            _tokens("[TITLEPATH]") = NotNull(_gameInfo.TitlePath, "")
            If _tokens("[TITLEPATH]") <> "" Then
                Dim paths() As String = IO.Directory.GetFiles(_gameInfo.TitlePath, _tokens("[ROMBARE]") & ".*")
                If paths.Length > 0 Then 'if at least one file is found do something
                    _tokens("[TITLEIMG]") = Path.GetFileName(paths(0))
                End If
            End If
        Catch ex As Exception
            _log.err("In tokens contruction: " & ex.Message & vbCr & ex.StackTrace)
        End Try
        _tokens("[GECMDLINE]") = NotNull(_gameInfo.CmdLine, "")

        _db.echo(".")
        _db.echo("Qlaunch, Unzip, Mount: " & SysSetup("UseQuicklaunch") & ", " &
         SysSetup("ROMSZipped") & ", " & EmuSetup("ImageMount"))
        _db.echo("Disable QLaunch, Disable Mount: " & EmuSetup("DisableQL") & ", " &
                 Game("DisableMount"))

        ' ============================ QUICKLAUNCH Folder ================================
        msg.ChangeMsg("Quicklaunch Folder checks...", 1)
        _log.echo("")
        _db.echo("QUICKLAUNCH: " & SysSetup("UseQuicklaunch").ToString & "; Emu disable: " & EmuSetup("DisableQL").ToString, False, "quicklaunch process")
        _log.echo("QUICKLAUNCH PROCEEDURES:")
        _log.echo("System Use Quicklaunch:" & SysSetup("UseQuicklaunch").ToString)
        _log.echo("Emu Disable Quicklaunch:" & EmuSetup("DisableQL").ToString)
        If SysSetup("UseQuicklaunch") = True And (EmuSetup("DisableQL") = False Or IsDBNull(EmuSetup("DisableQL"))) Then
            _log.echo("Quicklaunch set to true and not disabled by Emu....")
            UsingQL = True
            CleanFolderName = CleanFolderString(_romName)
            _log.echo("Clean Folder name: " & CleanFolderName)
            _log.echo("Checking if folder already exists....")
            If Directory.Exists(SysSetup("QuicklaunchRoot") & "\" & CleanFolderName) Then

                _log.echo("Folder already exists. Checking if files exist...")
                GameQLDir = SysSetup("QuicklaunchRoot") & "\" & CleanFolderName

                If Directory.GetFiles(GameQLDir).Length = 0 Then
                    _log.echo("No files in this directory. Flag to files not extant...")
                    msg.ChangeMsg("Folder Exists but no files...", 2)
                Else
                    _log.echo("Files exist. Flag to true...")
                    msg.ChangeMsg("Folder and Files exist...", 2)
                    QLFilesExtant = True
                End If

            Else
                _log.echo("Quicklaunch folder DOES NOT exist. Creating...")
                Directory.CreateDirectory(SysSetup("QuicklaunchRoot") & "\" & CleanFolderName)
                GameQLDir = SysSetup("QuicklaunchRoot") & "\" & CleanFolderName
                msg.ChangeMsg("Creating Folder...", 2)
            End If
            _tokens("[QLAUNCHGAME]") = GameQLDir
        Else
            _log.echo("Quicklaunch set to False and not disabled by Emu. Setting Launch path to Rom Path.")
            GameQLDir = SysSetup("ROMSZipped")
            _tokens("[QLAUNCHGAME]") = ""
            msg.ChangeMsg("Quicklaunch false. Using ROM...", 2)
        End If

        'SKIP MOUNT
        If SkipMount = True Then
            _log.echo(".")
            _log.echo("SKIP MOUNT = True - skipping to launch support apps.")
            _log.echo("Tokens at skip:")
            For Each token As KeyValuePair(Of String, String) In _tokens
                _log.echo(token.Key & ": " & token.Value)
            Next
            GoTo SkipMount
        End If

        '================ QUICKLAUNCH Unzip / MOve File=================================
        _db.echo("Files in QL; ROMS Zipped: " & QLFilesExtant.ToString & ", " & SysSetup("ROMSZipped").ToString, False, "unzip")
        _log.echo("Number files in Quicklaunch Folder: " & QLFilesExtant.ToString)

        If QLFilesExtant = False And SysSetup("UseQuicklaunch") And Not (EmuSetup("DisableQL")) = True Then
            _log.echo("Use Quicklaunch TRUE, no files in QL Folder and QL NOT disabled in Emu. Moving files for unzip....")

            If EmuSetup("UnzipROM") = True Then
                ' UNZIP ROM
                _log.echo("Unzip Quicklaunch ROM TRUE in Emu Setup")
                _log.echo("UNZIP PROCESS START")
                msg.ChangeMsg("Unzipping ROM File...", 1)
                msg.ChangeMsg("", 2)

                'PakiISO etc:
                CopyDirectory(GEmvoy.GameExPath & "\PLUGINS\GEmvoy\PakkISO", GameQLDir, True)

                '  Dim systempfolder As String = SysSetup("QuicklaunchRoot")
                Dim systempfolder As String = Path.GetTempPath()
                systempfolder = systempfolder.Remove(systempfolder.Length - 1) ' removes the trailing "/"

                _log.echo("Using Temp Path: " & systempfolder)
                Dim UsingTempFile As Boolean = False
                Dim RomFolder As String = SysSetup("RomsFolder")

                'Determine if rom on Client or network:
                If System.IO.Path.IsPathRooted(SysSetup("RomsFolder")) Then
                    Dim drive As New System.IO.DriveInfo(System.IO.Path.GetPathRoot(SysSetup("RomsFolder")))
                    ' do something
                    If drive.DriveType = System.IO.DriveType.Network Then
                        _log.echo("ROM is on a NETWORK drive. Checking copy to local setting...")
                        If GEmvoy.Setts.NetZipToLocal = False Then
                            _log.echo("Copy to local set to false - unzipping from Network drive to Local with Local 7z.")
                        Else
                            _log.echo("Copy to local set to TRUE. Copying zip to Quicklaunch temp directory")
                            msg.ChangeMsg("Copying Network ROM File...", 1)
                            msg.ChangeMsg("", 2)

                            Dim CopyArgs As New WorkerArgs
                            With CopyArgs
                                .Arg1 = RomFolder & "\" & _romName
                                .Arg2 = systempfolder & "\" & _romName
                            End With

                            _log.echo("COPY START")
                            CopyBG.RunWorkerAsync(CopyArgs)
                            While CopyBG.IsBusy
                                Windows.Forms.Application.DoEvents()
                            End While
                            _log.echo("COPY END")

                            RomFolder = systempfolder
                            UsingTempFile = True
                        End If
                    Else
                        _log.echo("ROM is on a LOCAL drive")
                    End If
                Else
                    _log.echo("Path doesn't start with ""\"" or Drive Letter (not rooted)")
                End If

                finalsize = UnzippedSize(RomFolder & "\" & _romName)

                msg.ChangeMsg("Unzipping ROM File...", 1)
                msg.ChangeMsg("", 2)
                unziptimer.Enabled = True
                unziptimer.Start()

                Unzip.RunWorkerAsync(RomFolder)

                While Unzip.IsBusy
                    Windows.Forms.Application.DoEvents()
                End While

                unziptimer.Stop()

                'Check if Net>Local copy done - is so - delete temp
                If UsingTempFile = True Then
                    System.IO.File.Delete(systempfolder & "\" & _romName)
                End If

                'msg.ProgressBar1.Visible = False
                msg.ChangeMsg("", 2)

                _log.echo("Unzip Finished. Return code: " & UZipExit)
                If UZipExit > 0 Then
                    _log.echo("Unzip finished in error - prompting user + ceasing game Launch....")
                    _log.echo("GAME LAUNCH ABANDONED")
                    _log.echo("====================================")
                    _log.echo("ERROR: Problem unzipping the file: " & SysSetup("RomsFolder") & "\" & _romName)
                    _log.echo("Use QL(sys), Disable QL (EMU), Emu: " & SysSetup("UseQuicklaunch") &
                              ", " & EmuSetup("DisableQL") & ", " & EmuSetup("Name"))
                    msg.ChangeMsg("ERROR: Unzip Failed. See log.", 2)
                    Threading.Thread.Sleep(5000)
                    msg.Close()
                    'Delete QL Folder
                    Try
                        Directory.Delete(_tokens("[QLAUNCHGAME]"), True)
                        _log.echo("Defective Quicklaunch folder deleted.")
                    Catch
                        _log.echo("ERROR: Whilst deleting quickalunch folder - please check + delete manually if neccessary")
                    End Try
                    Game("QuickLaunchPrompt") = "Ask"
                    Return
                End If

                ' ================== Check for ECM Files + UnECM if extant ==============================
                _db.echo("Using Directory: " & GameQLDir, False, "ECM Process")

                Dim files() As String
                files = Directory.GetFiles(GameQLDir, "*.ecm", SearchOption.TopDirectoryOnly)
                For Each FileName As String In files
                    _db.echo("Procesign file: " & FileName)
                    'Do Something With The File  
                    msg.ChangeMsg("Processing ECM Files...", 1)
                    UnEcm.RunWorkerAsync()
                    While UnEcm.IsBusy
                        Windows.Forms.Application.DoEvents()
                    End While
                    'Delete the ECM file
                    DeleteFilesFromFolder(GameQLDir, "ecm")

                Next
                _db.echo("UnECM Finished.")

                ' =================== Process any APE files ==============================
                _db.echo("", False, "process ape files")
                Dim Dir As New IO.DirectoryInfo(GameQLDir)
                Dim allFiles As IO.FileInfo() = Dir.GetFiles("*.ape")
                Dim singleFile As IO.FileInfo
                Dim FileNoExt As String = Nothing

                For Each singleFile In allFiles
                    _db.echo("Name:" & singleFile.Name)
                    _db.echo("----")
                    FileNoExt = Path.GetFileNameWithoutExtension(singleFile.Name)
                    msg.ChangeMsg("Processing APE Files...", 1)
                    msg.ChangeMsg("Processing: " & singleFile.Name, 2)
                    UnApe.RunWorkerAsync(FileNoExt)
                    While UnApe.IsBusy
                        Windows.Forms.Application.DoEvents()
                    End While
                    msg.ChangeMsg("Tidying up...", 2)
                Next
                DeleteFilesFromFolder(GameQLDir, "ape")
                DeleteFilesFromFolder(GameQLDir, "wav")
                _db.echo("UnApe Finished.")

                File.Delete(GameQLDir & "\MAC.exe")
                File.Delete(GameQLDir & "\sox.exe")
                File.Delete(GameQLDir & "\unecm.exe")

                _log.echo("UNZIP PROCESS FINISHED")

            Else
                'COPY ROM FILE
                _log.echo("Unzip Quicklaunch ROM FALSE in Emu Setup. Assuming means move Zipped ROM to Quickalunch Folder.")
                File.Copy(SysSetup("RomsFolder") & "\" & _romName, GameQLDir & "\" & _romName)
                msg.ChangeMsg("Moving ROM to Quicklaunch Folder...", 1)
                msg.ChangeMsg("", 2)
            End If

        Else
            _log.echo("Ether Ql set to false or files already in QL folder. Leaving as is.....")
        End If

        ' ========== DETERMINE LAUNCHFILE
        _log.echo(".")
        _log.echo("DETERMINE LAUNCH FILE")
        _log.echo("ImgMount: " & EmuSetup("ImageMount"))
        _log.echo("Disbale Mount: " & Game("DisableMount"))
        _log.echo("Use QLaunch: " & SysSetup("UseQuicklaunch"))
        _log.echo("Diasbale QLaunch: " & EmuSetup("DisableQL"))

        msg.ChangeMsg("Determining Launchfile..", 1)
        msg.ChangeMsg("", 2)

        If EmuSetup("ImageMount") And Not (Game("DisableMount")) Then
            _log.echo("Use image mount")

            If SysSetup("UseQuicklaunch") And Not (EmuSetup("DisableQL")) Then
                _log.echo("Use Quicklaunch")
                'Launchfile to pririty file in QL folder
                Launchfile = PriotityFile(GameQLDir)
            Else
                _log.echo("DONT USE Quicklaunch")
                'Launchfile to file in original roms directory
                Launchfile = SysSetup("RomsFolder") & "\" & _romName
            End If

        Else
            _log.echo("Do not use image mount")

            If SysSetup("UseQuicklaunch") And Not (EmuSetup("DisableQL")) Then
                _log.echo("Use Quicklaunch")
                'Launchfile to pririty file in QL folder
                Launchfile = PriotityFile(GameQLDir)
            Else
                _log.echo("DONT USE Quicklaunch")
                Launchfile = SysSetup("RomsFolder") & "\" & _romName
            End If

        End If

        If Launchfile = Nothing Then
            _log.err("Final launchfile was nothing. Likely no file of ascibed extentions available. Check setup")
            _log.echo("Error in identifying suitable file to boot. Check the Launch Folder and also the files therein to check that there is a file of one of the identified extentions for this emulator. Not booting Emulator and proceeding with game boot shutdown.")
            _log.echo("ROMFolder: " & SysSetup("RomsFolder") & " || Quicklaunch: " & NotNull(GameQLDir, ""))

            msg.ChangeMsg("ERROR: Launchfile failed. See log.", 2)
            Threading.Thread.Sleep(5000)
            msg.Close()

            Return
        End If

        _log.echo("Final Launchfile: " & Launchfile)
        msg.ChangeMsg("Launchfile determined.", 2)
        _log.echo(".")

        'Lineup any needed tokens
        _tokens("[LAUNCHFILE]") = Launchfile
        _log.echo(".")

        _tokens("[ROMUSED]") = Path.GetFileName(Launchfile)
        _tokens("[PATHUSED]") = Path.GetDirectoryName(Launchfile)

        '  ========== LOAD PER_GAME SETTINGS 
        _log.echo("LOAD ANY EMULATOR SETTINGS")
        _log.echo("Sys, Emu, Game IDs: " &
                 CInt(SysSetup("ID")) & ", " &
                 CInt(EmuSetup("ID")) & ", " &
                 CInt(Game("ID")))
        _log.echo("Use Settings Algo?: " & EmuSetup("UseSettsAlgo"))

        If NotNull(EmuSetup("UseSettsAlgo"), False) = True Then
            _log.echo("Use Emulator Settings Algorithm set to TRUE. Running routine...")
            msg.ChangeMsg("Loading Emulator Settings...", 1)
            msg.ChangeMsg("", 2)
            Try
                LoadSettings(CInt(SysSetup("ID")), CInt(EmuSetup("ID")), CInt(Game("ID")),
                             False, False, False, GEmvoy.Setts.SuppSettsAudio)
            Catch ex As Exception
                _log.echo(ex.Message, True)
                _log.echo(ex.StackTrace, True)
                msg.Close()
            End Try
        Else
            _log.echo("Emulator Settings Algorithm NOT used...")
        End If


        ' ======== MOUNT IMAGE if Mount Image selected]
        _log.echo("")
        _log.echo("MOUNT IMAGE if selected")
        _log.echo("EmuSetup Mount; Game Mount disable: " & EmuSetup("ImageMount") & ", " & Game("DisableMount"))

        If EmuSetup("ImageMount") = True And Game("DisableMount") = False Then

            _log.echo("Image mount routine started..")
            msg.ChangeMsg("Mount Image Process", 1)

            selrow = _ds.Tables("VirtualDrives").Select("ID = '" & EmuSetup("VDriveID") & "'")
            VDrive = selrow(0)
            _log.echo("VDrive Selected from Emu Setup: " & VDrive("Name"))

            'PRE MOUNT STUFF
            _log.echo("Any pre-mount checks/actions...")
            Select Case VDrive("Product")

                Case "DaemonToolsLite"
                    _log.echo("DTools Used. Premount process:")
                    Dim PreMount As New ProcessStartInfo
                    With PreMount
                        .FileName = VDrive("Exe")
                        .Arguments = "-remove_all"
                        .WindowStyle = ProcessWindowStyle.Hidden
                        .WorkingDirectory = Path.GetDirectoryName(VDrive("Exe"))
                    End With
                    ' Remove all drives:
                    Dim DoPreMount As Process = Process.Start(PreMount)
                    If Not DoPreMount.WaitForExit(10000) Then
                        _log.echo("Virtual Drive removal took too long...")
                    Else
                        _log.echo("All virtual drives removed..")
                    End If
                    wait(200)
                    _log.echo("Now create Vdrive with: " & VDrive("Exe") & " " & "-add " & EmuSetup("DriveType"))
                    PreMount.Arguments = "-add " & EmuSetup("DriveType")
                    DoPreMount = Process.Start(PreMount)
                    If Not DoPreMount.WaitForExit(10000) Then
                        _log.echo("Add new VDrive took too long...")
                    Else
                        _log.echo("New " & EmuSetup("DriveType") & " Drive Added")
                    End If

            End Select

            ' Check drive not in use...
            '_log.echo("Testing Drive for pre-existing mount: " & EmuSetup("DriveLetter"))
            'If IO.Directory.Exists(EmuSetup("DriveLetter") & ":\") Then
            '    Dim cdrom As New IO.DriveInfo(EmuSetup("DriveLetter") & ":")
            '    _log.echo("Drive Exists. Volume details:")
            '    _log.echo("Drive.totalsize= " & cdrom.TotalSize)
            '    _log.echo("Drive.isready= " & cdrom.IsReady)
            '    _log.echo("Drive type: " & cdrom.DriveType)
            '    _log.echo("Drive format: " & cdrom.DriveFormat)
            '    _log.echo("Drive label: " & cdrom.VolumeLabel)
            '    _log.echo("Drive Name: " & cdrom.Name)
            '    ' If _LeaveMounted = False Then
            '    msg.ChangeMsg("Clearing drive....", 2)
            '    UnMount.RunWorkerAsync()
            '    While UnMount.IsBusy
            '        Windows.Forms.Application.DoEvents()
            '    End While
            '    msg.ChangeMsg("", 2)
            '    'End If

            '    ' MsgBox("unmounted?")
            '    'A disc is in the drive and it's ready to be accessed
            'Else
            '    _log.echo("No image mounted...")
            '    'End If
            'End If
            wait(200)
            msg.ChangeMsg("Mouting Image....", 2)
            _log.echo("Mounting Image...")

            Mount.RunWorkerAsync()

            While Mount.IsBusy
                Windows.Forms.Application.DoEvents()
            End While
            msg.ChangeMsg("Image Mounted.", 2)

            _log.echo("Image mounted.")
            ImgMounted = True
        Else
            _log.echo("ImgMount set to false or disable set to true - NOT mounting")
        End If

        ' ========== POPULATE COMMAND LINE
        _log.echo("")
        _log.echo("CONSTRUCT FINAL COMMAND LINE")
        _log.echo("Final tokens:")
        msg.ChangeMsg("Constructing Command line...", 1)
        msg.ChangeMsg("", 2)
        For Each token As KeyValuePair(Of String, String) In _tokens
            _log.echo(token.Key & ": " & token.Value)
        Next

        Dim cmdDrive As String = Microsoft.VisualBasic.Left(Path.GetPathRoot(EmuSetup("Exe")), 2)
        Dim ExeRoot As String = Path.GetDirectoryName(EmuSetup("Exe"))

        _log.echo("")
        _log.echo("Cmd Line components:")
        _log.echo("GameCmd: " & Game("CmdLine"))
        _log.echo("FullBootCmd: " & EmuSetup("FullBootParams"))
        _log.echo("SetupCmd: " & EmuSetup("SetupBootParams"))
        _log.echo("Emu Drive: " & cmdDrive)
        _log.echo("Emu Path: " & ExeRoot)


        Dim CmdLineJig As String = Nothing
        Dim CmdLineOut As String = Nothing

        'Constuct exe part:
        CmdLineOut = cmdDrive & " & " & "cd """ & ExeRoot & """ & """ & EmuSetup("Exe") & """ "
        _cmdexe = EmuSetup("Exe")

        If Game("CmdLine") <> "" Then
            CmdLineJig = Game("CmdLine")
        ElseIf _BootCmd = True Then
            CmdLineJig = EmuSetup("FullBootParams")
        Else
            CmdLineJig = EmuSetup("SetupBootParams")
        End If
        _log.echo("Cmd line model: " & CmdLineJig)

        'Replace tokens and append to command line:
        CmdLineOut = CmdLineOut & ReplaceTokens(CmdLineJig)
        _cmdparams = ReplaceTokens(CmdLineJig)
        _log.echo(">> FINAL CMD: ")
        _log.echo(CmdLineOut)
        _tokens("[GEMCMDLINE]") = CmdLineOut
        _cmdLine = CmdLineOut

        ' ======================== KEY MAPPINGS =====================================
        _log.echo("")
        _log.echo("KEYMAPS")
        'Construct KeyMap:
        ConstructKeyMap()

        'Keyhook:
        'Test if any remappings:
        _db.echo("Keys Count: " & KeysDC.Count)
        If KeysDC.Count > 0 Then
            _log.echo("There are key remaps - start Keyhook")
            msg.ChangeMsg("Starting Key remaps...", 1)
            msg.ChangeMsg("", 2)
            kHook.InstallHook()
        Else
            _log.echo("There are NO key remaps - ensure no keyhooks running")
            If kHook.State = True Then
                kHook.RemoveHook()
            End If
        End If

        '=========== SUPPORT APPS =======================================================
SkipMount:
        ' Construst SApps table
        msg.ChangeMsg("Support Apps...", 1)
        msg.ChangeMsg("Discerning Apps..", 2)

        _log.echo(".")
        _log.echo("SUPPORT APPS")
        ' _log.echo("Sys,Emu,Game IDs for support apps: " & SysSetup("ID") & ", " & EmuSetup("ID") & ", " & Game("ID"))
        Try
            SAppsDT.Clear()
            Dim newrow As DataRow
            Dim Hit As Boolean = False
            Dim sarow() As DataRow = Nothing
            For Each ssrow As DataRow In _ds.Tables("SysSetup_Support").Rows
                newrow = SAppsDT.NewRow
                Hit = False
                ' _log.echo("ROW Sys,Emu,Game IDs: " & ssrow("SysSetupID") & ", " & ssrow("EmuSetupID") & ", " & ssrow("GameID"))

                If NotNull(ssrow("EmuSetupID"), -1) = EmuSetup("ID") Or
                    NotNull(ssrow("SysSetupID"), -1) = SysSetup("ID") Then
                    If Game("SuppSupportApps") = False Then
                        Hit = True
                    End If
                End If

                If NotNull(ssrow("GameID"), -1) = Game("ID") Then
                    Hit = True
                End If

                If Hit Then
                    _db.echo("HIT!")
                    _db.echo("Wait to Finish: " & ssrow("WaitToFinish"))
                    sarow = _ds.Tables("SupportApps").Select("ID = '" & ssrow("SupportAppID") & "'")
                    newrow("SSID") = ssrow("ID")
                    newrow("Timing") = NotNull(ssrow("Timing"), "Before")
                    newrow("SpecificParams") = NotNull(ssrow("SpecificParams"), "")
                    newrow("AppVisibility") = NotNull(ssrow("AppVisibility"), "Normal")
                    newrow("WaitToFinish") = NotNull(ssrow("WaitToFinish"), False)
                    newrow("WaitForIdle") = NotNull(ssrow("WaitForIdle"), False)
                    newrow("Name") = NotNull(sarow(0)("Name"), "{ERROR - NO NAME SET}")
                    newrow("Exe") = NotNull(sarow(0)("Exe"), "{ERROR - NO EXE SET}")
                    newrow("DefaultParams") = NotNull(sarow(0)("DefaultParams"), "")
                    newrow("QuitWithGemvoy") = NotNull(sarow(0)("QuitWithGemvoy"), True)
                    SAppsDT.Rows.Add(newrow)
                End If
            Next

        Catch ex As Exception
            _db.echo(ex.Message, True)
            _db.echo(ex.StackTrace, True)
            msg.Close()
        End Try

        _log.echo("SupportApps query completed successfully")
        _log.echo("Number of rows: " & SAppsDT.Rows.Count)
        PrintTableOrView(SAppsDT, "Support apps datatable")

        'Launch relevant support apps
        _log.echo("Lanching any apps....")
        Try
            For Each approw As DataRow In SAppsDT.Rows
                _db.echo("approw: " & approw("Name"))
                _db.echo("Wait to Finish?: " & approw("WaitToFinish"))
                If approw("Timing") = "Before" Then
                    Dim finalparam As String = ReplaceTokens(approw("DefaultParams"))
                    If Not (String.IsNullOrEmpty(approw("SpecificParams").ToString().Trim)) Then finalparam = ReplaceTokens(approw("SpecificParams"))

                    Dim SApp As New ProcessStartInfo
                    With SApp
                        .FileName = approw("Exe")
                        .Arguments = finalparam
                        .WindowStyle = ReturnWindowStyle(approw("AppVisibility"))
                    End With

                    Dim SuppAppsArgs As New WorkerArgs

                    SuppAppsArgs.Arg1 = SApp

                    If approw("WaitToFinish") = True Then
                        _db.echo("Wait to finish on support app...")
                        _log.echo("Started 'wait to finish' app: " & approw("Name"))
                        _log.echo("Window: " & approw("AppVisibility"))
                        msg.ChangeMsg("Awaiting 'Wait to finish' App end...", 2)

                        SuppAppsArgs.Arg2 = True
                        SupportApp.RunWorkerAsync(SuppAppsArgs)
                        While SupportApp.IsBusy
                            Windows.Forms.Application.DoEvents()
                        End While

                    ElseIf approw("WaitForIdle") = True Then

                        _db.echo("Wait for idle on support app...")
                        _log.echo("Started 'wait for idle' app: " & approw("Name"))
                        _log.echo("Window: " & approw("AppVisibility"))
                        msg.ChangeMsg("Awaiting 'Wait for Idle' App to get idle...", 2)

                        SuppAppsArgs.Arg2 = False
                        SuppAppsArgs.Arg3 = True
                        SupportApp.RunWorkerAsync(SuppAppsArgs)
                        While SupportApp.IsBusy
                            Windows.Forms.Application.DoEvents()
                        End While
                        _log.echo("App [" & approw("Name") & "] no longer idle")

                    Else

                        msg.ChangeMsg("Launching App...", 2)
                        _log.echo("Started app: " & approw("Name"))
                        _log.echo("Window: " & approw("AppVisibility"))
                        SuppAppsArgs.Arg2 = False
                        SuppAppsArgs.Arg3 = False
                        SupportApp.RunWorkerAsync(SuppAppsArgs)

                    End If



                End If
                For i As Integer = 0 To 5
                    Application.DoEvents()
                    Threading.Thread.Sleep(100)
                Next
                'MsgBox("Pause")
            Next
        Catch ex As Exception
            _db.echo(ex.Message, True)
            _db.echo(ex.StackTrace, True)
            msg.Close()
        End Try

        If SkipMount = True Then
            MsgBox("Fake Boot. Click OK to simulate close of emulator. Ensure any support apps have completed their process.", MsgBoxStyle.Exclamation)
            _log.echo(".")
            _log.echo("SKIP MOUNT = True - exiting Launch Routine.")
            msg.Close()
            Return
        End If

        ' ============== CAM SNAPS =============================================
        _log.echo(".")
        _log.echo("CAM SNAPS")
        _log.echo("Enabled, Usehotkey, GEActivated: " & GEmvoy.Setts.CamEnabled & ", " &
                  GEmvoy.Setts.CamUseHotkey & ", " & GEmvoy.GECamEnabled)
        _log.echo("Use Cam number: " & GEmvoy.Setts.CamNumber)
        _log.echo("Cams:")

        Dim count As Integer = 0
        For Each cam As WebEye.Controls.WinForms.WebCameraControl.WebCameraId In WCFeed.GetVideoCaptureDevices
            Cams.Add(cam)
            _log.echo(count & ": " & cam.Name)
            count += 1
        Next

        If (GEmvoy.Setts.CamEnabled = True And GEmvoy.Setts.CamUseHotkey = False) Or
            (GEmvoy.Setts.CamEnabled = True And GEmvoy.Setts.CamUseHotkey = True And GEmvoy.GECamEnabled = True) Then
            msg.ChangeMsg("Starting Cam Snaps...", 1)
            msg.ChangeMsg("", 2)
            Try
                WCFeed.StartCapture(Cams(GEmvoy.Setts.CamNumber))
                _log.echo("Cam Started successfully. Starting Capture..")
                _log.echo("Capturing: " & WCFeed.IsCapturing)
                _log.echo("Snaps root: " & GEmvoy.Setts.CamPath)
                CamSnap.RunWorkerAsync(NotNull(EmuSetup("DisablePIP"), False))
                msg.ChangeMsg("Started successfully..", 2)
            Catch ex As Exception
                _log.echo("ERROR: Error starting Cam. CAPTURE ABORTED.")
                _log.echo(ex.Message, True)
                _log.echo(ex.StackTrace, True)
                msg.ChangeMsg("Error starting cam..", 2)
                'e.Cancel = True
            End Try
        Else
            _log.echo("Settings/setup don't enable cam...")
        End If

        ' ============== END LAUNCH PROCESS =============================================
        _log.echo(".")
        _log.echo("PRE-LAUNCH CHECKS")
        If File.Exists(Launchfile) Then
            _log.echo("Launchfiles exists: " & Launchfile)
            msg.ChangeMsg("Launching Game...", 1)
            msg.ChangeMsg("", 2)
        Else
            _log.err("Launchfile DOES NOT exist. Launchfile: " & Launchfile)
            My.Computer.Audio.PlaySystemSound(System.Media.SystemSounds.Exclamation)

            msg.ChangeMsg("ERROR - No Gamefile", 1)
            msg.ChangeMsg("Check Launchfile in log.", 2)
            wait(5000)
        End If


        msg.Close()
        _log.echo(".")
        _log.echo("GAME LAUNCH COMPLETED")
        _log.echo("====================================")
        _log.echo("")

    End Sub

    Private Sub wait(ByVal interval As Integer)
        Dim sw As New Stopwatch
        sw.Start()
        Do While sw.ElapsedMilliseconds < interval
            ' Allows UI to remain responsive
            Application.DoEvents()
        Loop
        sw.Stop()
    End Sub

    Public Function MakeCPWBSafe(ByVal str As String) As String

        'remove brackets
        If GEmvoy.Setts.StripBrackets = True Then
            str = Regex.Replace(str, "\[(.*?)\]", "")
            str = Regex.Replace(str, "\((.*?)\)", "")
        End If

        'str = str.Replace("\\(.+\\)", "")
        ' str = str.Replace("\\[[^\\(]*\\]", "")
        Dim strIllegalChars As String = "^()[]${}*|<>"
        'If str.Contains("!") Then
        '    str = str.Replace("!", "")
        'End If
        For Each c As Char In strIllegalChars
            If str.Contains(c.ToString) Then
                str = str.Replace(c.ToString, "-")
            End If
        Next
        str = str.Trim()
        Return str
    End Function


    Public Function MakeSQLSafe(ByVal sql As String) As String
        'first i'd avoid putting quote chars in as they might be valid? just double them up.
        Dim strIllegalChars As String = "/?-^%{}[];$=*`#|&@\<>()+,\"
        'replace single quotes with double so they don't cause escape character
        If sql.Contains("'") Then
            sql = sql.Replace("'", "''")
        End If
        'need to double up double quotes from what I remember to get them through
        'If sql.Contains("""") Then
        '    sql = sql.Replace("""", """""")
        'End If
        'remove illegal chars
        'For Each c As Char In strIllegalChars
        '    If sql.Contains(c.ToString) Then
        '        sql = sql.Replace(c.ToString, "")
        '    End If
        'Next

        Return sql
    End Function

    Private Sub ConstructKeyMap()

        _db.echo("")
        _db.echo("", False, "construct keymap")
        GKeyMap = New KeyMap()
        KeyLookup = New List(Of Integer)

        'check if supress enabled for emu - if so - select from game alone
        Dim selterm As String = Nothing
        selterm = "GameID = '" & Game("ID") & "'"
        If Game("SuppKeyRemaps") = False Then
            selterm = selterm & " OR EmuSetupID = '" & EmuSetup("ID") & "'"
        End If
        _db.echo("Final Select used on keymap:" & selterm)

        Dim selrow() As DataRow = _ds.Tables("KeyRemaps").Select(selterm)
        Try
            If selrow.Count > 0 Then
                _db.echo("KEY REMAP ROWS EXIST")

                Dim output As String = Nothing

                For Each col As DataColumn In _ds.Tables("KeyRemaps").Columns
                    output = output & ", " & col.ColumnName
                Next
                output = output & vbCr
                _db.echo(output)

                Dim Keyrow() As DataRow = Nothing

                'Public KeyLookup As New List(Of Integer)
                'Public GKeyMap As New KeyMap
                'Public KeysDC As New Dictionary(Of Integer, List(Of Object))
                'Public KeysTest As New Dictionary(Of Integer, Boolean) ' boolean - Modifiers present for this key

                Dim count As Integer = 0

                For Each row As DataRow In selrow

                    PrintTableRow(row)

                    Dim values As New List(Of Object)
                    Keyrow = _ds.Tables("Keys").Select("ID = '" & row("ToKeyID") & "'")
                    '  GKeyMap.ToKeycode = Keyrow(0).Item("ID")
                    values.Add(Keyrow(0).Item("WinKeyCode")) ' To Code
                    values.Add(row("FromAlt"))
                    values.Add(row("FromCtrl"))
                    values.Add(row("FromShift"))
                    values.Add(row("ToAlt"))
                    values.Add(row("ToCtrl"))
                    values.Add(row("ToShift"))
                    values.Add(row("KeyPress"))
                    values.Add(row("Pause"))

                    Keyrow = _ds.Tables("Keys").Select("ID = '" & NotNull(row("ModKeyID"), -1) & "'")
                    If Keyrow.Count > 0 Then
                        values.Add(Keyrow(0).Item("WinKeyCode")) ' Mod WinCode
                    Else
                        values.Add(-1)
                    End If

                    Keyrow = _ds.Tables("Keys").Select("ID = '" & row("FromKeyID") & "'")
                    values.Add(Keyrow(0).Item("WinKeyCode")) ' From WinCode

                    values.Add(Keyrow(0).Item("FriendlyName")) ' Name

                    KeysDC.Add(count, values) ' HERE???

                    'Test if FromKey already added (as Dictionary key)
                    If KeysTest.ContainsKey(Keyrow(0).Item("WinKeyCode")) Then
                        _db.echo("Primary Input Key already mapped - setting value to minus to indicate other mappings available. Modifier: " &
                                 row("ModKeyID"))
                        KeysTest(Keyrow(0).Item("WinKeyCode")) = -count
                    Else
                        _db.echo("Input key not yet mapped - setting value to KeysDict key")
                        KeysTest.Add(Keyrow(0).Item("WinKeyCode"), count)
                    End If

                    'GKeyMap.FromKeycode = Keyrow(0).Item("ID")
                    count = count + 1
                Next

                'KeyLookup.Sort()

            Else
                _db.echo("No key remaps")
            End If



        Catch ex As Exception
            _db.echo(ex.Message, True)
            _db.echo(ex.StackTrace, True)
        End Try

    End Sub



    Private Declare Function GetKeyState Lib "user32.dll" (ByVal key As Keys) As Short

    Private Sub kHook_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles kHook.KeyDown

        'Public KeyLookup As New List(Of Integer)
        'Public GKeyMap As New KeyMap
        'Public KeysDC As New Dictionary(Of Integer, List(Of Object))
        'Public KeysTest As New Dictionary(Of Integer, Boolean) ' boolean - Modifiers present for this key

        Try

            ' _db.echo("")
            '_db.echo("KeyCode: " & e.KeyCode, False, "Keydown Keyhook triggered")
            If SendingKey = True Then
                _db.echo("Sendingkey flag to true - return without proceeding")
                Return
            End If

            Dim KeyIn As Integer = e.KeyCode

            If (KeyIn = 16 Or KeyIn = 17 Or KeyIn = 18) Then
                If GetKeyState(Keys.LShiftKey) < 0 Then
                    KeyIn = 160
                ElseIf GetKeyState(Keys.LControlKey) < 0 Then
                    KeyIn = 162
                ElseIf GetKeyState(Keys.RControlKey) < 0 Then
                    KeyIn = 163
                ElseIf GetKeyState(Keys.RShiftKey) < 0 Then
                    KeyIn = 161
                ElseIf GetKeyState(Keys.LMenu) < 0 Then
                    KeyIn = 164
                ElseIf GetKeyState(Keys.RMenu) < 0 Then
                    KeyIn = 165
                End If
            End If

            '  _db.echo("Key in after Controls check: " & KeyIn)

            If Not (KeysTest.TryGetValue(KeyIn, Nothing)) Then
                _db.echo("Key In not mapped - return")
                Return
            Else
                '_db.echo("Key In Map - proceed")
            End If

            _db.echo("KeyCode: " & e.KeyCode, False, "Keydown Keyhook triggered")


            Dim KMVals As List(Of Object) = Nothing
            Dim SingleVals As List(Of Object) = Nothing
            'Find Rifght Kvals (from either single instance or set)
            If KeysTest(KeyIn) >= 0 Then
                _db.echo("Only one key mapping for this input key..")
                KMVals = KeysDC(KeysTest(KeyIn))
            Else
                _db.echo("MORE THAN ONE key mapping for this input key..")
                For Each KeyDCVals As List(Of Object) In KeysDC.Values
                    If KeyDCVals(10) = KeyIn Then
                        _db.echo("Vals set found for Keyin. ModKey: " & KeyDCVals(9))
                        If KeyDCVals(9) = -1 Then
                            _db.echo("-1 indicates no mod key. Record as single keypress - can be modified later..")
                            SingleVals = KeyDCVals
                        Else
                            If KeyOut.InputDeviceState.IsKeyDown(KeyDCVals(9)) Then
                                _db.echo("Mod Key down. Setting Vals to this")
                                KMVals = KeyDCVals
                                Exit For
                            End If
                        End If
                    End If

                Next
            End If

            If KMVals Is Nothing And SingleVals Is Nothing Then
                _db.echo("Neither modded or single key in ID'd. Returning - no keymap.")
                Return
            ElseIf KMVals Is Nothing Then
                KMVals = SingleVals
            End If

            _db.echo("Final Key In: " & KMVals(11))

            _db.echo("KM1,2,3: " & KMVals(1) & ", " & KMVals(2) & ", " & KMVals(3))
            _db.echo("Alt,Ctrl,Shift: " & e.Alt & ", " & e.Control & ", " & e.Shift)

            'TEST any control key requirements in From Key - return if mismatch
            If KMVals(1) <> e.Alt Or KMVals(2) <> e.Control Or KMVals(3) <> e.Shift Then
                _db.echo("From Controls not matched - RETURN")
                Return
            End If


            'SEND KEY
            'Block original key:
            e.Handled = True

            _db.echo("KMVals length: " & KMVals.Count)
            _db.echo("Final Key Out: " & KMVals(0))

            'GKeyMap = New KeyMap()

            '0 -("ToKeyWinCode"))     
            '1 -("FromAlt"))
            '2 -("FromCtrl"))
            '3 -("FromShift"))
            '4 -("ToAlt"))
            '5 -("ToCtrl"))
            '6 -("ToShift"))
            '7 -("KeyPress"))
            '8 -("Pause"))
            '9 - ModKeyCode
            '10 - FromKeyWinCode
            '11 - Friendly name

            Dim kc As New KeysConverter
            ' Dim Sinp As New SendInputs
            Select Case KMVals(7)
                Case "Press"
                    _db.echo("Method = 'Press'")
                    SendingKey = True

                    If (KMVals(4) Or KMVals(5) Or KMVals(6)) Then
                        Dim newlist As List(Of VirtualKeyCode) = ControlVcodes(KMVals(4), KMVals(5), KMVals(6))
                        KeyOut.Keyboard.ModifiedKeyStroke(newlist, Convert.ToInt32(KMVals(0)))
                    Else
                        KeyOut.Keyboard.KeyPress(KMVals(0))

                        'SendKeys.SendWait("q")
                        'SendInputs.SendKey("Q")

                        'SendKBInput(KEYEVENTF.EXTENDEDKEY, Keys.Q)
                        'SendKBInput(KEYEVENTF.KEYUP, Keys.Q)

                    End If
                    SendingKey = False
                Case "Down"
                    _db.echo("Method = 'Down'")
                    SendingKey = True
                    KeyOut.Keyboard.KeyDown(KMVals(0))
                    SendingKey = False
                Case "Up"
                    _db.echo("Method = 'Up'")
                    SendingKey = True
                    KeyOut.Keyboard.KeyUp(KMVals(0))
                    SendingKey = False
                    '    'TO DO:
                Case "Down,Up"
                    '_db.echo("Method = 'Down,Up'")
                    'SendingKey = True
                    'KeyOut.Keyboard.KeyDown(KMVals(0))
                    'Threading.Thread.Sleep((KMVals(8)))
                    'KeyOut.Keyboard.KeyUp(KMVals(0))
                    'SendingKey = False
                Case "Toggle"
                    _db.echo("Method = 'Toggle'")
                    If KeyOut.InputDeviceState.IsHardwareKeyDown(KMVals(0)) Then
                        SendingKey = True
                        KeyOut.Keyboard.KeyUp(KMVals(0))
                        SendingKey = False
                    Else
                        SendingKey = True
                        KeyOut.Keyboard.KeyDown(KMVals(0))
                        SendingKey = False
                    End If
            End Select

        Catch ex As Exception
            _db.echo(ex.Message, True)
            _db.echo(ex.StackTrace, True)
        End Try

    End Sub

    <DllImport("user32.dll")> _
    Private Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function SetForegroundWindow(hWnd As IntPtr) As Boolean
    End Function

    Public Sub Start()
        Dim zero As IntPtr = IntPtr.Zero
        Dim i As Integer = 0
        While (i < 60) AndAlso (zero = IntPtr.Zero)
            Threading.Thread.Sleep(500)
            zero = FindWindow(Nothing, "YourWindowName")
            i += 1
        End While
        If zero <> IntPtr.Zero Then
            SetForegroundWindow(zero)
            SendKeys.SendWait("{TAB}")
            SendKeys.SendWait("{TAB}")
            SendKeys.SendWait("{ENTER}")
            SendKeys.Flush()
        End If
    End Sub


    Public Sub ResponsiveSleep(ByRef iMilliSeconds As Integer)
        Dim i As Integer, iHalfSeconds As Integer = iMilliSeconds / 500
        For i = 1 To iHalfSeconds
            Threading.Thread.Sleep(500) : Application.DoEvents()
        Next i
    End Sub

    Private Function ControlVcodes(alt As Boolean, ctrl As Boolean, shift As Boolean) As List(Of VirtualKeyCode)

        Dim retlist As New List(Of VirtualKeyCode)
        If alt Then retlist.Add(VirtualKeyCode.MENU)
        If ctrl Then retlist.Add(VirtualKeyCode.CONTROL)
        If shift Then retlist.Add(VirtualKeyCode.SHIFT)
        Return retlist

    End Function

    Private Sub SupportApp_dowork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        _log.echo("Starting SupportApp background worker")
        Dim args As WorkerArgs = DirectCast(e.Argument, WorkerArgs)

        Dim SApp As ProcessStartInfo = DirectCast(args.Arg1, ProcessStartInfo)
        Dim WaitForExit As Boolean = DirectCast(args.Arg2, Boolean)
        Dim WaitForIdle As Boolean = DirectCast(args.Arg3, Boolean)

        _log.echo("Exe: " & SApp.FileName)
        _log.echo("Args: " & SApp.Arguments)
        _log.echo("Win: " & SApp.WindowStyle)

        'Dim DoSApp As Process = Process.Start(SApp)
        If WaitForExit = True Then
            _log.echo("Starting App as Wait for Exit")
            Process.Start(SApp).WaitForExit()
        ElseIf WaitForIdle = True Then
            _log.echo("Starting App as Wait for Idle")
            ProcList.Add(Process.Start(SApp))
        Else
            'no wait for exit or idle
            _log.echo("Starting App and adding to list")
            ProcList.Add(Process.Start(SApp))
        End If
        'MsgBox("input idle!")

        'DoSApp.WaitForExit()

    End Sub

    Private Function ReturnWindowStyle(style As String) As ProcessWindowStyle
        Select Case style
            Case "Normal"
                Return ProcessWindowStyle.Normal
            Case "Hidden"
                Return ProcessWindowStyle.Hidden
            Case "Maximized"
                Return ProcessWindowStyle.Maximized
            Case "Minimized"
                Return ProcessWindowStyle.Minimized
        End Select
        Return ProcessWindowStyle.Normal
    End Function

    Private Sub PrintTableOrView(ByVal table As DataTable, ByVal label As String)
        Dim sw As System.IO.StringWriter
        Dim output As String = Nothing

        ' _log.echo("", False, label)

        'Table Header
        For Each col As DataColumn In table.Columns
            output = output & ", " & col.ColumnName
        Next

        _log.echo(output)
        output = Nothing

        ' Loop through each row in the table. '
        For Each row As DataRow In table.Rows
            sw = New System.IO.StringWriter
            ' Loop through each column. '
            For Each col As DataColumn In table.Columns
                ' Output the value of each column's data.
                sw.Write(row(col).ToString() & ", ")
            Next
            output = sw.ToString
            ' Trim off the trailing ", ", so the output looks correct. '
            If output.Length > 2 Then
                output = output.Substring(0, output.Length - 2)
            End If
            ' Display the row in the console window. '
            _log.echo(output)
        Next
        _log.echo("")
    End Sub

    Private Sub PrintTableRow(ByVal row As DataRow)
        Dim sw As System.IO.StringWriter
        Dim output As String = Nothing

        ' Loop through each row in the table. '

        sw = New System.IO.StringWriter
        ' Loop through each column. '
        For Each col As Object In row.ItemArray
            ' Output the value of each column's data.
            sw.Write(col.ToString() & ", ")
        Next
        output = sw.ToString
        ' Trim off the trailing ", ", so the output looks correct. '
        If output.Length > 2 Then
            output = output.Substring(0, output.Length - 2)
        End If
        ' Display the row in the console window. '
        _db.echo(output)

        _db.echo("")
    End Sub

    Private Function NotNull(Of T)(ByVal Value As T, ByVal DefaultValue As T) As T

        If Value Is Nothing OrElse IsDBNull(Value) Then
            Return DefaultValue
        Else
            Return Value
        End If
    End Function

    Private Function ReplaceTokens(Tokenised As String) As String

        _db.echo("In: " & Tokenised, False, "replace tokens routine")
        Dim RetStr As String = Nothing
        RetStr = Tokenised


        For Each token As KeyValuePair(Of String, String) In _tokens


            Try

                RetStr = Replace(RetStr, token.Key, _tokens(token.Key))
                _db.echo(token.Key & ": " & token.Value)

            Catch ex As Exception
                _log.err("Occurred during tokens Replacement")
                _log.echo(ex.Message, True)
                _log.echo(ex.StackTrace, True)
            End Try


        Next





        'RetStr = Replace(RetStr, "[VDRIVELTR]", _tokens("[VDRIVELTR]"))
        'RetStr = Replace(RetStr, "[VDRIVETYPE]", _tokens("[VDRIVETYPE]"))
        'RetStr = Replace(RetStr, "[LAUNCHFILE]", _tokens("[LAUNCHFILE]"))

        _db.echo("Out: " & RetStr)

        Return RetStr
    End Function

    Private Function PriotityFile(TargetDir As String) As String
        _db.echo("EmuName: " & EmuSetup("Name"), False, "Determine priority file")

        Dim ExtPrty As New Dictionary(Of Integer, String)
        Dim PriorityFile As String = Nothing

        Dim Extrows() As DataRow = Nothing
        Extrows = _ds.Tables("EmuSetup_FileExts").Select("EmuSetupID = '" & EmuSetup("ID") & "'", "Priority DESC")
        Dim FileExts() As DataRow = Nothing
        Dim Prty As Integer
        Dim Ext As String

        If Extrows.Count = 0 Then
            Log.echo("No file extentions set for emulator. Inform User and return....")
            MsgBox("There are no File Extentions setup for this Emulator. Please check in GEmvoy.")
        End If

        For Each Extrow As DataRow In Extrows
            Prty = Extrow.Item("Priority")
            FileExts = _ds.Tables("FileExts").Select("ID = '" & Extrow.Item("FileExtID") & "'")
            Ext = FileExts(0).Item("Ext")
            _db.echo("Priotirty, Ext: " & Prty & ", " & Ext)
            For Each _file As String In Directory.GetFiles(TargetDir, "*." & Ext)
                _db.echo("File: " & _file)
                PriorityFile = _file
            Next
        Next

        _db.echo("Priority File at end of process: " & PriorityFile)

        Return PriorityFile

    End Function

    Private Sub CopyBG_dowork(ByVal sender As Object, ByVal e As DoWorkEventArgs)

        Dim args As WorkerArgs = e.Argument
        Dim FromFile As String = args.Arg1
        Dim ToFile As String = args.Arg2

        _db.echo("Copy BG Worker Started. Recived: " & vbCr & FromFile & vbCr & ToFile)
        Try
            Dim sr As New IO.FileStream(FromFile, IO.FileMode.Open, FileAccess.Read)
            Dim sw As New IO.FileStream(ToFile, IO.FileMode.Create)
            Dim len As Long = sr.Length - 1
            Dim buffer(1048576) As Byte
            Dim bytesread As Integer

            While sr.Position < len
                bytesread = (sr.Read(buffer, 0, 1048576))
                sw.Write(buffer, 0, bytesread)

                ' msg.ChangeMsg("Unzipping...", 2)
                ' ProgressBar1.Value = CInt(sr.Position / len * 100)
                'msg.Msg2LB.Text = sr.Position & " / " & len
                msg.Msg2LB.Text = Math.Round(sr.Position / 1048576) & "M / " & Math.Round(len / 1048576) & "M"
                Application.DoEvents()
            End While

            sw.Flush()
            sw.Close()
            sr.Close()
            'File.Copy(FromFile, ToFile, True)

        Catch ex As Exception
            _log.echo(ex.Message, True)
            _log.echo(ex.StackTrace, True)
        End Try

    End Sub

    Private Sub CopyTimerTick() Handles CopyTimer.Tick
        _db.echo("Timer tick..")

        'Dim pressize As Long = GetFolderSize(GameQLDir & "\GEmvoyTemp")

        Dim infoReader As System.IO.FileInfo
        infoReader = My.Computer.FileSystem.GetFileInfo(GameQLDir & "\GEmvoyTemp\" & _romName)
        Dim pressize As Long = infoReader.Length
        _db.echo("final size:" & finalsize)
        _db.echo("Pres size:" & pressize)
        If pressize < finalsize Then
            _db.echo("Timer Tick. New Size: " & pressize)
            'msg.ProgressBar1.Value = pressize
            msg.Msg2LB.Text = Math.Round(pressize / 1048576) & "M / " & Math.Round(finalsize / 1048576) & "M"
        End If

    End Sub

    Private Sub UnZip_dowork(ByVal sender As Object, ByVal e As DoWorkEventArgs)

        Dim RomsFolder As String = DirectCast(e.Argument, String)
        _log.echo("UnZip BG worker process started. RomsFoldr: " & RomsFolder)
        Dim Uzip As New ProcessStartInfo
        Dim FullROMPath As String = RomsFolder & "\" & _romName
        _log.echo("Unzipping using:")
        _log.echo("""" & GEmvoy.Setts.ZipExe & """ e """ & FullROMPath & """ -o""" & GameQLDir & """")
        _db.echo("7z: " & GEmvoy.Setts.ZipExe)

        If GEmvoy.Setts.UnzipProg = True Then
            With Uzip
                .FileName = Path.GetDirectoryName(GEmvoy.Setts.ZipExe) & "\7zG.exe"
                .Arguments = "e """ & FullROMPath & """ -o""" & GameQLDir & """ -r -aoa"
            End With
        Else
            With Uzip
                .FileName = GEmvoy.Setts.ZipExe
                .Arguments = "e """ & FullROMPath & """ -o""" & GameQLDir & """ -y -r -aoa"
                .UseShellExecute = False
                .CreateNoWindow = True
                .RedirectStandardOutput = True
                .WindowStyle = ProcessWindowStyle.Hidden
            End With

        End If

        If Not (File.Exists(Uzip.FileName)) Then
            Log.echo("ERROR: Either 7z.exe or 7zG.exe doens't exist - prompted user..")
            MsgBox("GEmvoy cannot find the 7z executable. Please check path set in Settings and then the 7z installaion.", MsgBoxStyle.Exclamation, "7Zip Error")
            UZipExit = 1
            Return
        End If
        'Using out = New StreamWriter("C:\Dev\test.txt")
        '    AddHandler myprocess.OutputDataReceived, write7zout()

        '    myprocess.Start()
        '    myprocess.BeginOutputReadLine()
        '    myprocess.WaitForExit()
        'End Using

        Dim DoUZip As Process = Process.Start(Uzip)
        '  DoUZip.Start()
        '   DoUZip.BeginOutputReadLine()
        If Not DoUZip.WaitForExit(120000) Then
            _log.echo("Unzip took too long...")
        Else
            'dunno
        End If

        UZipExit = DoUZip.ExitCode

    End Sub

    Sub write7zout(ByVal sender As Object, ByVal e As Object)
        sender.WriteLine(e.Data)
    End Sub

    Private Sub UnEcm_dowork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        _db.echo("Starting UNecm background worker")
        Dim Uecm As New ProcessStartInfo
        With Uecm
            .FileName = GameQLDir & "\unecm.exe"
            .Arguments = "*.ecm"
            If GEmvoy.Setts.ShowUnECM = True Then
                .WindowStyle = ProcessWindowStyle.Normal
            Else
                .WindowStyle = ProcessWindowStyle.Hidden
            End If
            .WorkingDirectory = GameQLDir
        End With
        ' Process.Start(Uecm)`
        Dim DoUecm As Process = Process.Start(Uecm)
        If Not DoUecm.WaitForExit(120000) Then
            MsgBox("UnECM took too long...")
        Else
            _db.echo(".")
        End If
    End Sub

    Private Sub UnAPE_dowork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim ApeFile As String = DirectCast(e.Argument, String) ' without extention
        _db.echo("Starting UnAPE background worker")
        Dim UApe As New ProcessStartInfo

        With UApe
            .FileName = GameQLDir & "\mac.exe"
            .Arguments = """" & ApeFile & ".ape"" """ & ApeFile & ".wav"" -d"
            If GEmvoy.Setts.ShowUnECM = True Then
                .WindowStyle = ProcessWindowStyle.Normal
            Else
                .WindowStyle = ProcessWindowStyle.Hidden
            End If
            .WorkingDirectory = GameQLDir
        End With
        ' Process.Start(Uecm)`
        Dim DoUApe As Process = Process.Start(UApe)
        If Not DoUApe.WaitForExit(120000) Then
            _db.echo("UnAPE took too long on .ape > .wav. Exiting...")
        Else
            _db.echo(".")
        End If

        With UApe
            .FileName = GameQLDir & "\sox.exe"
            .Arguments = """" & ApeFile & ".wav"" -t raw -s -c 2 -w -r 44100 """ & ApeFile & ".bin"""
            If GEmvoy.Setts.ShowUnECM = True Then
                .WindowStyle = ProcessWindowStyle.Hidden
            Else
                .WindowStyle = ProcessWindowStyle.Normal
            End If
            .WorkingDirectory = GameQLDir
        End With
        ' Process.Start(Uecm)`
        DoUApe = Process.Start(UApe)
        If Not DoUApe.WaitForExit(120000) Then
            _db.echo("UnAPE took too long on .wav > .bin. Exiting...")
        Else
            _db.echo(".")
        End If

    End Sub

    Private Sub Mount_dowork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        '_db.echo("Starting Mount background worker")
        Dim Mount As New ProcessStartInfo
        With Mount
            .FileName = VDrive("Exe")
            .Arguments = ReplaceTokens(VDrive("MountCmd"))
            If GEmvoy.Setts.ShowUnECM = True Then
                .WindowStyle = ProcessWindowStyle.Hidden
            Else
                .WindowStyle = ProcessWindowStyle.Normal
            End If
            .WorkingDirectory = Path.GetDirectoryName(VDrive("Exe"))
        End With
        _log.echo("Mounting with cmd: ")
        _log.echo("""" & VDrive("Exe") & """ " & Mount.Arguments.ToString)
        ' Process.Start(Uecm)`
        Dim DoMount As Process = Process.Start(Mount)
        If Not DoMount.WaitForExit(10000) Then
            _log.echo("Mount took too long...")
        Else
            ' _db.echo(".")
        End If

        ' DToolsReturn = DoMount.ExitCode
        'MsgBox(DoMount.ExitCode)
        _log.echo("FINISHED Mount background worker")

    End Sub

    Private Sub UnMount_dowork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        _db.echo("Starting UNMOUNT background worker")
        Dim UnMount As New ProcessStartInfo
        With UnMount
            .FileName = VDrive("Exe")
            .Arguments = ReplaceTokens(VDrive("UnmountCmd"))
            If GEmvoy.Setts.ShowUnECM = True Then
                .WindowStyle = ProcessWindowStyle.Hidden
            Else
                .WindowStyle = ProcessWindowStyle.Normal
            End If
            .WorkingDirectory = Path.GetDirectoryName(VDrive("Exe"))
        End With
        ' Process.Start(Uecm)`
        Dim DoUnMount As Process = Process.Start(UnMount)
        If Not DoUnMount.WaitForExit(120000) Then
            MsgBox("UNMount took too long...")
        Else
            _db.echo(".")
        End If
    End Sub

    Sub DeleteFilesFromFolder(Folder As String, Ext As String)

        For Each _file As String In Directory.GetFiles(Folder, "*." & Ext)
            File.Delete(_file)
        Next
        For Each _folder As String In Directory.GetDirectories(Folder)
            DeleteFilesFromFolder(_folder, Ext)
        Next

    End Sub

    Sub CopyDirectory(ByVal SourcePath As String, ByVal DestPath As String, Optional ByVal Overwrite As Boolean = False)
        Dim SourceDir As DirectoryInfo = New DirectoryInfo(SourcePath)
        Dim DestDir As DirectoryInfo = New DirectoryInfo(DestPath)

        ' the source directory must exist, otherwise throw an exception
        If SourceDir.Exists Then
            ' if destination SubDir's parent SubDir does not exist throw an exception
            If Not DestDir.Parent.Exists Then
                Throw New DirectoryNotFoundException _
                  ("Destination directory does not exist: " + DestDir.Parent.FullName)
            End If

            If Not DestDir.Exists Then
                DestDir.Create()
            End If

            ' copy all the files of the current directory
            Dim ChildFile As FileInfo
            For Each ChildFile In SourceDir.GetFiles()
                If Overwrite Then
                    ChildFile.CopyTo(Path.Combine(DestDir.FullName, ChildFile.Name), True)
                Else
                    ' if Overwrite = false, copy the file only if it does not exist
                    ' this is done to avoid an IOException if a file already exists
                    ' this way the other files can be copied anyway...
                    If Not File.Exists(Path.Combine(DestDir.FullName, ChildFile.Name)) Then
                        ChildFile.CopyTo(Path.Combine(DestDir.FullName, ChildFile.Name), False)
                    End If
                End If
            Next

            ' copy all the sub-directories by recursively calling this same routine
            Dim SubDir As DirectoryInfo
            For Each SubDir In SourceDir.GetDirectories()
                CopyDirectory(SubDir.FullName, Path.Combine(DestDir.FullName, _
                  SubDir.Name), Overwrite)
            Next
        Else
            Throw New DirectoryNotFoundException("Source directory does not exist: " + SourceDir.FullName)
        End If
    End Sub

    Private Function CleanFolderString(raw As String)
        For Each c As Char In IO.Path.GetInvalidFileNameChars
            raw = raw.Replace(c, "")
        Next
        Return raw
    End Function

    Private Function AddGame(SysSetupID As Integer, EmuSetupID As Integer, pergamesetts As Boolean, EmuDefSettsID As Integer) As Integer
        _log.echo(">> Add New Game Routine")
        _log.echo("In:")
        _log.echo("SysSetupID: " & SysSetupID)
        _log.echo("EmuSetupID: " & EmuSetupID)
        _log.echo("pergamesetts: " & pergamesetts)
        _log.echo("EmuDefSettsID: " & EmuDefSettsID)

        Try
            'Dim SysSetupID As Integer = 0
            ' Dim EmuSetupID As Integer = 0
            Dim EmuName As String = ""
            Dim SysName As String = ""

            Dim query As Object

            Dim EmuToUse As Integer = -1
            If UseSpecificEmu = True And SpecdEmuSetupID > -1 Then
                'Use Specified Emulator
                query = From S In _ds.Tables("SystemsSetups").AsEnumerable()
                Let HolderVal = New With {.SpecdEmuSetupID = SpecdEmuSetupID}
                Where S.Field(Of Integer)("ID") = _sysSetupID
                Join E In _ds.Tables("EmuSetups").AsEnumerable()
                On E.Field(Of Integer)("ID") Equals HolderVal.SpecdEmuSetupID
                Select New With {
                    .SysSetupID = S.Field(Of Integer)("ID"),
                    .EmuSetupID = E.Field(Of Integer)("ID"),
                    .EmuName = E.Field(Of String)("Name"),
                    .SysName = S.Field(Of String)("Name")}
                'EmuToUse = SpecdEmuSetupID
            Else
                'Use Default Emulator for System Setup
                query = From S In _ds.Tables("SystemsSetups").AsEnumerable()
                Where S.Field(Of Integer)("ID") = _sysSetupID
                Join E In _ds.Tables("EmuSetups").AsEnumerable()
                On S.Field(Of Integer)("DefEmuSetupID") Equals E.Field(Of Integer)("ID")
                Select New With {
                    .SysSetupID = S.Field(Of Integer)("ID"),
                    .EmuSetupID = E.Field(Of Integer)("ID"),
                    .EmuName = E.Field(Of String)("Name"),
                    .SysName = S.Field(Of String)("Name")}
            End If

            ' HERE - change value of DEFEMUSEUP IF PRESCRIBED EMU
            'query = From S In _ds.Tables("SystemsSetups").AsEnumerable()
            '            Where S.Field(Of Integer)("ID") = _sysSetupID
            '            Join E In _ds.Tables("EmuSetups").AsEnumerable()
            '            On S.Field(Of Integer)("DefEmuSetupID") Equals E.Field(Of Integer)("ID")
            '            Select New With {
            '                .SysSetupID = S.Field(Of Integer)("ID"),
            '                .EmuSetupID = E.Field(Of Integer)("ID"),
            '                .EmuName = E.Field(Of String)("Name"),
            '                .SysName = S.Field(Of String)("Name")}

            _db.echo("Query completed successfully. Outcomes:")

            For Each item As Object In query
                _db.echo("Item: " & item.ToString)
                EmuSetupID = item.EmuSetupID
                SysSetupID = item.SysSetupID
                EmuName = item.EmuName
                SysName = item.SysName
            Next

            _db.echo("Query results populate done..")

            _log.echo("Gamename: " & _gameInfo.GameName)

            Dim newrow As DataRow = _ds.Tables("Games").NewRow


            newrow.Item("EditedGameName") = MakeCPWBSafe(Path.GetFileNameWithoutExtension(_romName))
            newrow.Item("GEGameName") = "" & MakeCPWBSafe(_gameInfo.GameName)
            newrow.Item("EmuSetupID") = EmuSetupID
            newrow.Item("SysSetupID") = SysSetupID
            newrow.Item("RomFile") = _romName
            newrow.Item("UniqueGameName") = _romName & " [" & EmuName & "] -- [" & SysName & "]"     'EDIT THIS _ EXTENTION MISSING!
            newrow.Item("CmdLine") = ""
            newrow.Item("QuickLaunchPrompt") = "As per System Setup"
            newrow.Item("DisableSettsHx") = False
            newrow.Item("DisableMount") = False
            newrow.Item("SuppSupportApps") = False
            newrow.Item("SuppKeyRemaps") = False
            newrow.Item("EmuSettsID") = 0
            newrow.Item("EmuSettProfileID") = 0
            newrow.Item("EmuSettPGAlgo") = False
            newrow.Item("EmuSettsOveride") = False
            newrow.Item("DefaultForGame") = False


            _db.echo("New row lined up.")

            _ds.Tables("Games").Rows.Add(newrow)


            Dim selrow() As DataRow
            selrow = _ds.Tables("Games").Select("RomFile = '" & MakeSQLSafe(_romName) & "' AND EmuSetupID = '" & EmuSetupID & "' AND SysSetupID = '" & SysSetupID & "'")
            _log.echo("ID: " & selrow(0).Item("ID"))

            Dim GameID As Integer = selrow(0).Item("ID")

            'DETERMINE EMU_SETTS_ID
            Dim match As Boolean
            Dim gsrow As DataRow = _ds.Tables("EmuSettsProfile").NewRow

            For Each crow As DataRow In _ds.Tables("EmuSettsProfile").Rows
                If CInt(GameID) = NotNull(crow("GameID"), -1) And crow("Name") = "Game Default" Then
                    match = True
                    Exit For
                End If
            Next

            Dim nrow As DataRow

            If match = False Then
                gsrow("Name") = "Game Default"
                gsrow("GameID") = GameID
                _ds.Tables("EmuSettsProfile").Rows.Add(gsrow)
                'Now update Games record if UsePerGame = true or EmuSetsOverride = true
                nrow = _ds.Tables("Games").Select("ID = " & GameID)(0)
                Dim srow As DataRow = _ds.Tables("EmuSettsProfile").Select("GameID = " & GameID)(0)
                If pergamesetts Then
                    nrow("EmuSettProfileID") = srow("ID")
                Else
                    nrow("EmuSettProfileID") = EmuDefSettsID
                End If
            End If

            _log.echo("New Game Profile successfully written: " & newrow.Item("UniqueGameName"))

            _db.echo("Determine ID of new Game Profile to return")


            Return selrow(0).Item("ID")

            'Save Database:
            GameEx.Plugin.GEmvoy.QuickSaveXML()

        Catch ex As Exception
            _log.echo(ex.Message, True)
            _log.echo(ex.StackTrace, True)
        End Try

    End Function


    Public Sub SaveSettings(SysID As Integer, EmuID As Integer, GameID As Integer,
                            Optional ForceEmuSave As Boolean = False,
                            Optional ForceGameSave As Boolean = False,
                            Optional SuppressAudio As Boolean = False)

        If SysID = -1 Or EmuID = -1 Or GameID = -1 Then
            _log.echo("ERROR: Main.SaveSettings - sys,emu or gameID null")
            MsgBox("Cannot save Emu Settings at this time. There needs to be a game selected to do so...", MsgBoxStyle.Exclamation, "Emu Settings Error.")
            Return
        End If

        _log.echo("")
        _log.echo("", "Save Emulator Settings")
        Dim Sys() As DataRow = _ds.Tables("SystemsSetups").Select("ID = " & SysID)
        Dim Emu() As DataRow = _ds.Tables("EmuSetups").Select("ID = " & EmuID)
        Dim Game() As DataRow = _ds.Tables("Games").Select("ID = " & GameID)
        _log.echo("System: " & Sys(0)("Name"))
        _log.echo("Emu: " & Emu(0)("Name"))
        _log.echo("Game: " & Game(0)("UniqueGameName"))
        _log.echo("ForceEmuSave? " & ForceEmuSave)
        _log.echo("FoarceGameSave? " & ForceGameSave)
        _log.echo("PerGameSettings? " & Emu(0)("PerGameSetts"))
        _log.echo("EmuSettsOverride? " & Game(0)("EmuSettsOveride"))
        Dim EmuSetts() As DataRow
        Dim EmuSettsProf() As DataRow

        Dim path As String

        If (Emu(0)("PerGameSetts") = False And Game(0)("EmuSettsOveride") = False And ForceGameSave = False) Or ForceEmuSave = True Then

            ' ============== EMULATOR SETTINGS - EMU ONLY ===========================
            _db.echo("PerGameSetting to False OR EmuSave forced. Saving under Emulator Profile")

            EmuSetts = _ds.Tables("EmuSetts").Select("ID = " & NotNull(Emu(0)("EmuSettsID"), -1))
            EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("ID = " & NotNull(Emu(0)("EmuSettsProfileID"), -1))

            If EmuSetts.Count = 0 Then
                Log.err("No Emulator Settings Algorithm set in Emulator. Please revise. Settings NOT saved.")
                Return
            End If


            If EmuSettsProf.Count < 1 Then
                _db.echo("No return from Settings profile search. Setting to Default.", True)
                EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("EmuSetupID = " &
                                                                    NotNull(Emu(0)("ID"), -1) &
                                                                    " AND Name = 'Emulator Default'")
                _db.echo("Default EmuSettsProf no: " & EmuSettsProf(0)("ID"))
            End If

            path = GEmvoy.GameExPath & "\PLUGINS\GEmvoy\EmulatorSettings\" & SysID &
                     "\" & EmuID & "\xx_GEmvoyEmulatorProfiles_xx\" &
                     EmuSettsProf(0)("ID") & "\" & EmuSetts(0)("ID")

        Else
            ' ============== GAME SETTINGS - GAME ONLY ===========================
            _db.echo("Using Game Settings.....")

            _log.echo("Save PerGameSettings activated. Saving to Game Profile", "SAVING AS GAME SETTINGS")
            _log.echo("EmuSettsID from Games: " & NotNull(Game(0)("EmuSettsID"), -1))
            _log.echo("EmuSettsID from Emu: " & NotNull(Emu(0)("EmuSettsID"), -1))
            _log.echo("EmuSettsProfileID from Games: " & NotNull(Game(0)("EmuSettProfileID"), -1))
            _log.echo("Use Per-game algorithm?: " & Game(0)("EmuSettPGAlgo"))

            If Game(0)("EmuSettPGAlgo") Then
                _log.echo("Using per-game algorithm")
                EmuSetts = _ds.Tables("EmuSetts").Select("ID = " & NotNull(Game(0)("EmuSettsID"), -1))
            Else
                _log.echo("Using emulator algorithm")
                EmuSetts = _ds.Tables("EmuSetts").Select("ID = " & NotNull(Emu(0)("EmuSettsID"), -1))
            End If

            If EmuSetts.Count = 0 Then
                Log.err("No Emulator Settings Algorithm set in Game or Emulator Profile. Please revise. Settings NOT saved.")
                Return
            End If

            EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("ID = " & NotNull(Game(0)("EmuSettProfileID"), -1))

            If EmuSettsProf.Count < 1 Then
                _db.echo("No return from Settings profile search. Setting to Default.", True)
                EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("GameID = " &
                                                    NotNull(Game(0)("ID"), -1) &
                                                    " AND Name = 'Game Default'")
                _db.echo("Default EmuSettsProf no: " & EmuSettsProf(0)("ID"))
            End If

            path = GEmvoy.GameExPath & "\PLUGINS\GEmvoy\EmulatorSettings\" & SysID &
                 "\" & EmuID & "\" & GameID & "\" & EmuSettsProf(0)("ID") & "\" & EmuSetts(0)("ID")

            If Not (Directory.Exists(path)) Then
                Directory.CreateDirectory(path)
                Log.echo("No game directory for game profile. Creating.")
            End If

        End If

        If EmuSetts.Count < 1 Then
            _db.echo("Emulator Settings Algorithm not set - no returns on select..Can't proceed - returning", True)
            Return
        End If

        If Not (Directory.Exists(path)) Then
            _db.echo("Path didn't exist - creating")
            Directory.CreateDirectory(path)
        End If

        _log.echo("Using Algorithm: " & Emu(0)("EmuSettsID") & ". " & EmuSetts(0)("Name"))
        _log.echo("To Settings Profile: " & Emu(0)("EmuSettsProfileID") & ". " & EmuSettsProf(0)("Name"))
        _log.echo("Path: " & path)

        'EmuSave

        _db.echo("Checking Keep History....")
        If Emu(0)("KeepSettsHx") = True And Game(0)("DisableSettsHx") = False Then
            _log.echo("Keep Settings History enabled in Emu and not disabled in Game. Making backup of present to:")

            Dim BUFolder As String = DateTime.Now.ToString("yyyy-MM-dd_HH.mm.ss")
            Dim BUPath As String = path & "\xx_GEmvoyEmuProfileBackup_xx\" & BUFolder
            If Not (Directory.Exists(BUPath)) Then Directory.CreateDirectory(BUPath)
            _log.echo(BUPath)

            Dim counter As List(Of String) = Directory.GetDirectories(path & "\xx_GEmvoyEmuProfileBackup_xx").ToList
            Dim foldercount As Integer = counter.Count
            _db.echo("Number files in BU directory: " & counter.Count.ToString)
            Do Until foldercount < 6
                _log.echo("Number of backups over 5 - deleting...Folder Count: " & foldercount)

                Dim di As New DirectoryInfo(path & "\xx_GEmvoyEmuProfileBackup_xx")
                Dim dirs() As DirectoryInfo = di.GetDirectories()
                Dim creationTime As DateTime = DateTime.Now
                Dim oldestDir As DirectoryInfo = Nothing


                For Each dir As DirectoryInfo In dirs
                    If DateTime.Compare(dir.CreationTime(), creationTime) < 0 Then
                        oldestDir = dir
                        creationTime = dir.CreationTime()
                        _db.echo("(hit)")
                    End If
                Next
                Directory.Delete(oldestDir.FullName, True)
                foldercount = foldercount - 1

            Loop

            _log.echo("Making backup...")
            CopyDIRandExclude(path, BUPath, True, "xx_GEmvoyEmuProfileBackup_xx")

        Else
            _log.echo("Keep Settings History DISABLED.")
        End If

        _db.echo("Calling Save Settings Profile routine.")

        SaveSettsRoutine(EmuSetts(0)("ID"), path, Emu(0))

        If SuppressAudio = False Then
            My.Computer.Audio.Play(My.Resources.saved, AudioPlayMode.Background)
        End If

        _log.echo("", "<END> Save Emulator Settings")

    End Sub

    Public Sub LoadSettings(SysID As Integer, EmuID As Integer, GameID As Integer,
                            Optional ForceEmuLoad As Boolean = False, Optional ForceGameLoad As Boolean = False,
                            Optional UseDefaultEmu As Boolean = False, Optional SupressAudio As Boolean = False)

        _log.echo("")
        _log.echo("", "Load Emulator Settings")
        _log.echo("Sys,Emu,Game: " & SysID & ", " & EmuID & ", " & GameID)
        If SysID = -1 Or EmuID = -1 Or GameID = -1 Then
            _log.echo("ERROR: Main.LoadSettings - sys,emu or gameID null")
            MsgBox("Cannot Load Emu Settings at this time. There needs to be a game selected to do so...", MsgBoxStyle.Exclamation, "Emu Settings Error.")
            Return
        End If

        Dim Sys() As DataRow = _ds.Tables("SystemsSetups").Select("ID = " & SysID)
        Dim Emu() As DataRow = _ds.Tables("EmuSetups").Select("ID = " & EmuID)
        Dim Game() As DataRow = _ds.Tables("Games").Select("ID = " & GameID)

        _log.echo("System: " & Sys(0)("Name"))
        _log.echo("Emu: " & Emu(0)("Name"))
        _log.echo("Game: " & Game(0)("UniqueGameName"))
        _log.echo("ForceEmuSave? " & ForceEmuLoad)
        _log.echo("FoarceGameSave? " & ForceGameLoad)
        _log.echo("PerGameSettings? " & Emu(0)("PerGameSetts"))
        _log.echo("EmuSettsOverride? " & Game(0)("EmuSettsOveride"))

        Dim EmuSetts() As DataRow
        Dim EmuSettsProf() As DataRow

        Dim path As String = Nothing

        Dim LoadType As String = "none"
        Dim GameFolderErr As Boolean = False

        Dim files As Integer
        Dim cdirs As Integer

        _log.echo("PerGameSettings, Overide Emu Setts, ForeEmuLoad: " &
                Emu(0)("PerGameSetts") & "," &
                 Game(0)("EmuSettsOveride") & "," &
                 ForceEmuLoad)

        If ((Emu(0)("PerGameSetts") = True Or Game(0)("EmuSettsOveride") = True) And
             ForceEmuLoad = False) Or ForceGameLoad = True Then

            '  ============== EMULATOR SETTINGS - PER GAME  ==========================

            _log.echo("PerGameSetting conditionals met. Loading from Game Profile")
            _log.echo("EmuSettsID from Games: " & NotNull(Game(0)("EmuSettsID"), -1))
            _log.echo("EmuSettsID from Emu: " & NotNull(Emu(0)("EmuSettsID"), -1))
            _log.echo("EmuSettsProfileID from Games: " & NotNull(Game(0)("EmuSettProfileID"), -1))
            _log.echo("Use Per-game algorithm?: " & Game(0)("EmuSettPGAlgo"))

            If Game(0)("EmuSettPGAlgo") And NotNull(Game(0)("EmuSettsID"), -1) > 0 Then
                _log.echo("Using per-game algorithm as per Game Profile")
                EmuSetts = _ds.Tables("EmuSetts").Select("ID = " & NotNull(Game(0)("EmuSettsID"), -1))
            Else
                _log.echo("Either use pergame algo = false or no algo exists. Using Emu algo.")
                EmuSetts = _ds.Tables("EmuSetts").Select("ID = " & NotNull(Emu(0)("EmuSettsID"), -1))
            End If

            EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("ID = " & NotNull(Game(0)("EmuSettProfileID"), -1))

            If EmuSettsProf.Count < 1 Then
                _log.echo("No return from Settings profile search. Setting to Default.", True)
                EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("GameID = " &
                                                    NotNull(Game(0)("ID"), -1) &
                                                    " AND Name = 'Game Default'")
                _log.echo("Default EmuSettsProf no: " & EmuSettsProf(0)("ID"))
            End If

            If EmuSetts.Count = 0 Then
                Log.err("No Emulator Settings Algorithm set in Emulator. Please revise. Settings NOT saved.")
                Return
            End If

            'Test if profile used is actually an emu profile
            Try
                If IsDBNull(EmuSettsProf(0)("GameID")) Then
                    _log.echo("Setts Profile selected in Game Profile is an Emulator settings profile. Processing hereonin as emu setts profile.")

                    path = GEmvoy.GameExPath & "\PLUGINS\GEmvoy\EmulatorSettings\" & SysID &
                                        "\" & EmuID & "\xx_GEmvoyEmulatorProfiles_xx\" &
                                        EmuSettsProf(0)("ID") & "\" & EmuSetts(0)("ID")

                    _log.echo("PAth at this stage: " & path)

                    LoadType = "game"

                    If Not (Directory.Exists(path)) Then
                        Directory.CreateDirectory(path)
                        _log.echo("No game directory for game profile. Creating.")
                    End If
                    'now check Default or profile exists
                    files = System.IO.Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Count()
                    cdirs = System.IO.Directory.GetDirectories(path, "*", SearchOption.AllDirectories).Count()

                    If (files + cdirs = 0) Then
                        _log.echo("No files in game profile folder. Use Emu profile instead..")
                        LoadType = "emu"
                    End If

                Else
                    _log.echo("Setts Profile selected in Game Profile is a Game settings profile. Proceeding.")

                    path = GEmvoy.GameExPath & "\PLUGINS\GEmvoy\EmulatorSettings\" & SysID &
                         "\" & EmuID & "\" & GameID & "\" & EmuSettsProf(0)("ID") & "\" & EmuSetts(0)("ID")

                    _log.echo("PAth at this stage: " & path)

                    LoadType = "game"

                    If Not (Directory.Exists(path)) Then
                        Directory.CreateDirectory(path)
                        _log.echo("No game directory for game profile. Creating.")
                    End If
                    'now check Default or profile exists
                    files = System.IO.Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Count()
                    cdirs = System.IO.Directory.GetDirectories(path, "*", SearchOption.AllDirectories).Count()

                    If (files + cdirs = 0) Then
                        _log.echo("No files in game profile folder. Use Emu profile instead..")
                        LoadType = "emu"
                    End If


                End If
            Catch ex As Exception
                _log.echo(ex.Message, True)
                _log.echo(ex.StackTrace, True)
            End Try

        End If

        If (Emu(0)("PerGameSetts") = False And Game(0)("EmuSettsOveride") = False And ForceGameLoad = False) Or ForceEmuLoad = True Or LoadType = "emu" Then

            ' ============== EMULATOR SETTINGS - EMU ONLY ===========================
            _log.echo("PerGameSetting to False OR force Emul Load to True OR no files in per-game profile. Loading from Emulator Profile")

            EmuSetts = _ds.Tables("EmuSetts").Select("ID = " & NotNull(Emu(0)("EmuSettsID"), -1))

            If UseDefaultEmu = False Then
                'Use SettingsProfile specified in EmulatorSetup 
                _log.echo("Using SettingsProfile specified in EmulatorSetup ")
                EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("ID = " & NotNull(Emu(0)("EmuSettsProfileID"), -1))
            Else
                'Use the Default Emulator setup profile
                _log.echo("Use 'Emulator Defualt' Profile forced via method flag.")
                EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("EmuSetupID = " &
                                                      NotNull(Emu(0)("ID"), -1) &
                                                      " AND Name = 'Emulator Default'")
                ' EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("Name = 'Emulator Default'")
            End If

            If EmuSetts.Count = 0 Then
                Log.err("No Emulator Settings Algorithm set in Emulator. Please revise. Settings NOT loaded.")
                Return
            End If

            If EmuSettsProf.Count < 1 Then
                _log.echo("No return from Settings profile search. Setting to Default.", True)
                EmuSettsProf = _ds.Tables("EmuSettsProfile").Select("EmuSetupID = " &
                                                                    NotNull(Emu(0)("ID"), -1) &
                                                                    " AND Name = 'Emulator Default'")
                _log.echo("Default EmuSettsProf no: " & EmuSettsProf(0)("ID"))
            End If

            path = GEmvoy.GameExPath & "\PLUGINS\GEmvoy\EmulatorSettings\" & SysID &
                                "\" & EmuID & "\xx_GEmvoyEmulatorProfiles_xx\" &
                                EmuSettsProf(0)("ID") & "\" & EmuSetts(0)("ID")

            LoadType = "emu"

        End If

        _log.echo("Final profile type: " & LoadType.ToUpper)
        _log.echo("Final Profile used: " & EmuSettsProf(0)("ID") & ". " & EmuSettsProf(0)("Name"))
        _log.echo("Final Settings Group used: " & EmuSetts(0)("Name"))
        _log.echo("Final Path: " & path)

        If Not (Directory.Exists(path)) Then
            _log.err("The folder for the Emu/Game Settings Profile does not exist. Quitting Settngs Load. Essentially will just use whatwever settings are loaded at present to the emulator.. Please check: " & vbCr & path)
            'MsgBox("GEmvoy is set to Load emulator settings for this Emulator or Game. However, the settings folder is missing. Please re-populate the setting folder listed below via the GEmvoy Config application." & vbCr & vbCr & EmuSettsProf(0)("ID") & ". " & EmuSettsProf(0)("Name"), MsgBoxStyle.Exclamation, "Emulator Settings Load error.")
            Return
        Else
            _log.echo("Folder for Game/Emu Settings profile exists.")
        End If

        'Check that there ARE Settings in this folder
        files = System.IO.Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Count()
        cdirs = System.IO.Directory.GetDirectories(path, "*", SearchOption.AllDirectories).Count()
        If files + cdirs = 0 Then
            _log.err("GEmvoy set to use Emulator Settings Profile, but no .reg, files or folders in relevant folder: " & vbCr & path)
            Return
        Else
            _log.echo("There ARE files in the EmuSets Profile directory")
        End If

        LoadSettsRoutine(EmuSetts(0)("ID"), path, Emu(0))
        _log.echo("Load Emulator Settings completed successfully.")
        _log.echo("", "<end> Load Emulator Settings")

        If SupressAudio = False Then
            My.Computer.Audio.Play(My.Resources.loadprofile, AudioPlayMode.Background)
        End If

    End Sub

    Private Sub LoadSettsRoutine(EmuSettsID As Integer, path As String, EmuSetup As DataRow)
        _log.echo("Import Emu Setts Process:")
        _db.echo("SettsProfiID: " & EmuSetup("EmuSettsProfileID"))
        _db.echo("SettsAlgoID: " & EmuSetup("EmuSettsID"))

        Dim EmuSettsItems() As DataRow
        EmuSettsItems = _ds.Tables("EmuSettsItems").Select("EmuSettsID = " & EmuSettsID)

        '    {"Registry Item", "File", "Folder"}

        For Each row As DataRow In EmuSettsItems
            Select Case row("Type")

                Case "Registry Item"
                    _log.echo("Reg: " & path & "\" & row("ID") & ".reg")
                    'RegeditExport(row("ItemText"), path & "\" & row("ID") & ".reg")
                    RegeditImport(path & "\" & row("ID") & ".reg")

                Case "File"
                    Dim fileto As String = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(EmuSetup("Exe")),
                                                                    row("ItemText"))
                    Dim filefrom As String = path & "\" & System.IO.Path.GetFileName(row("ItemText"))
                    _log.echo("FileFrom: " & filefrom)
                    _log.echo("Save to: " & fileto)

                    My.Computer.FileSystem.CopyFile(
                        filefrom,
                        fileto,
                        Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs,
                        Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)

                Case "Folder"
                    Dim DirTo As String = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(EmuSetup("Exe")),
                                                                     row("ItemText"))
                    Dim DirFrom As String = path & "/" & System.IO.Path.GetFileName(row("ItemText"))
                    _log.echo("Dir: " & System.IO.Path.GetFileName(row("ItemText")))
                    _log.echo("Save to: " & DirTo)

                    Try
                        Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(
                            DirFrom,
                            DirTo, True)

                    Catch ex As Exception
                        _db.echo(ex.Message, True)
                        _db.echo(ex.StackTrace, True)
                        For Each key As Object In ex.Data.Keys
                            _db.echo(key.ToString() & ": " & ex.Data(key).ToString())
                        Next
                    End Try

            End Select
        Next

    End Sub

    Private Sub CopyDIRandExclude(FromDir As String, ToDir As String, Overwrite As Boolean, Optional ExcludeDir As String = "", Optional ExcludeFile As String = "")


        Dim SourceDir As DirectoryInfo = New DirectoryInfo(FromDir)
        Dim DestDir As DirectoryInfo = New DirectoryInfo(ToDir)

        If SourceDir.Exists Then

            Dim ChildFile As FileInfo
            For Each ChildFile In SourceDir.GetFiles()
                If File.Exists(Path.Combine(DestDir.FullName, ChildFile.Name)) Then
                    If ChildFile.Name <> ExcludeFile Then
                        ChildFile.CopyTo(Path.Combine(DestDir.FullName, ChildFile.Name), True)
                    End If
                Else
                    If Not File.Exists(Path.Combine(DestDir.FullName, ChildFile.Name)) Then
                        If ChildFile.Name <> ExcludeFile Then
                            ChildFile.CopyTo(Path.Combine(DestDir.FullName, ChildFile.Name), False)
                        End If

                    End If
                End If
            Next


            Dim SubDir As DirectoryInfo
            For Each SubDir In SourceDir.GetDirectories()
                If SubDir.Name <> ExcludeDir Then
                    CopyDirectory(SubDir.FullName, Path.Combine(DestDir.FullName, _
                    SubDir.Name), Overwrite)
                End If

            Next
        Else
            Throw New DirectoryNotFoundException("Source directory does not exist: " + SourceDir.FullName)
        End If
    End Sub

    Private Sub RegeditExport(sKey As String, sFilename As String)
        _log.echo("From: " & sKey)
        _log.echo("To: " & sFilename)

        Dim SApp As New ProcessStartInfo
        With SApp
            .FileName = "regedit.exe"
            .Arguments = " /s /e " & Chr(34) & sFilename & Chr(34) & " " & Chr(34) & sKey & Chr(34)
            .WindowStyle = ProcessWindowStyle.Hidden
        End With
        Process.Start(SApp)
        ' Shell("regedit.exe /s /e " & Chr(34) & sFilename & Chr(34) & " " & Chr(34) & sKey & Chr(34), vbHide)
    End Sub

    Private Sub RegeditImport(sFilename As String)
        _db.echo("Reg Import: " & sFilename)

        Dim SApp As New ProcessStartInfo
        With SApp
            .FileName = "regedit.exe"
            .Arguments = " /s /c " & Chr(34) & sFilename & Chr(34)
            .WindowStyle = ProcessWindowStyle.Hidden
        End With
        Process.Start(SApp)
        'Shell("C:\Windows\regedit.exe /s /c " & Chr(34) & sFilename & Chr(34), vbHide)
    End Sub

    Private Sub SaveSettsRoutine(EmuSettsID As Integer, path As String, EmuSetup As DataRow)
        _log.echo("Exporting: ", "Export Emu Settings Process")

        Dim EmuSettsItems() As DataRow
        EmuSettsItems = _ds.Tables("EmuSettsItems").Select("EmuSettsID = " & EmuSettsID)

        '    {"Registry Item", "File", "Folder"}

        For Each row As DataRow In EmuSettsItems
            Select Case row("Type")

                Case "Registry Item"
                    _log.echo("Reg: " & path & "\" & row("ID") & ".reg")
                    RegeditExport(row("ItemText"), path & "\" & row("ID") & ".reg")

                Case "File"
                    Dim filep As String = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(EmuSetup("Exe")),
                                                                    row("ItemText"))
                    _log.echo("File: " & filep)
                    _log.echo("Save to: " & path)
                    My.Computer.FileSystem.CopyFile(
                        filep,
                        path & "\" & System.IO.Path.GetFileName(filep),
                        Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs,
                        Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)

                Case "Folder"
                    Dim filep As String = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(EmuSetup("Exe")),
                                                                     row("ItemText"))
                    _log.echo("Folder: " & filep)
                    _log.echo("Save to: " & path)
                    My.Computer.FileSystem.CopyDirectory(
                        filep,
                        path & "\" & System.IO.Path.GetFileName(filep), True)
            End Select
            _log.echo("--")
        Next

    End Sub

#Region "Cam Snap Functions"

    Private Sub StartCamSnap(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Try

            Dim DisablePIP As Boolean = DirectCast(e.Argument, Boolean)

            _db.echo("========= Starting CamSnap ================")
            _db.echo("Emu Disable PIP: " & DisablePIP)
            Dim MinuteLimit As Integer = GEmvoy.Setts.CamCaptureFor
            Dim Unlimited As Boolean = False
            Dim Millitimer As Integer = GEmvoy.Setts.CamSnapGap
            Dim FinalFolder As String = GEmvoy.Setts.CamPath
            Dim SnapProb As Integer = GEmvoy.Setts.CamSnapProb
            Dim BurstNumber As Integer = GEmvoy.Setts.CamBurstNumber
            Dim BurstWait As Integer = GEmvoy.Setts.CamBurstWait

            Dim Bright As Integer = GEmvoy.Setts.CamBrightness
            Dim Contrast As Integer = GEmvoy.Setts.CamContrast
            Dim Gamma As Integer = GEmvoy.Setts.CamGamma
            Dim Red As Integer = GEmvoy.Setts.CamRed
            Dim Green As Integer = GEmvoy.Setts.CamGreen
            Dim Blue As Integer = GEmvoy.Setts.CamBlue
            Dim Timestamp As Boolean = GEmvoy.Setts.CamStamp
            Dim PIP As Boolean = GEmvoy.Setts.CamPIP

            _db.echo("SnapProbability: " & SnapProb)
            _db.echo("Minute Limit: " & MinuteLimit)
            _db.echo("Millitimer: " & Millitimer)
            _db.echo("Cam Used: " & GEmvoy.Setts.CamNumber)

            'For Each cam As WebEye.Controls.WinForms.WebCameraControl.WebCameraId In Cams
            '    _db.echo("Cam: " & cam.Name)
            'Next


            'camwindow.Show()

            ' *********** HERE - REINItiATE
            'Try
            '    WCFeed.StartCapture(Cams(GEmvoy.Setts.CamNumber))
            'Catch ex As Exception
            '    _db.echo("ERROR: Error starting Cam. Closing worker thread.")
            '    _db.echo(ex.Message, True)
            '    _db.echo(ex.StackTrace, True)
            '    Return
            '    'e.Cancel = True
            'End Try

            _db.echo("Cam Accessible: " & WCFeed.IsAccessible)
            _db.echo("Cam already capturing: " & WCFeed.IsCapturing)

            '   Dim WCImage As Bitmap


            'Detect if capture until game close
            If GEmvoy.Setts.CamCaptureFor = 0 Then
                _db.echo("Infinite capture detected")
                Unlimited = True
                MinuteLimit = 200
            End If
            _db.echo("Minute Limit: " & MinuteLimit)

            'CamSnapsFolder:
            If GEmvoy.Setts.CamDateFolder = True Then
                FinalFolder = GEmvoy.Setts.CamPath & "\" & DateTime.Now.ToString("yyMMdd")
                _db.echo("Final Folder: " & FinalFolder)
            End If
            If Not Directory.Exists(FinalFolder) Then
                _db.echo("Directory doesn't exist, creating...")
                Directory.CreateDirectory(FinalFolder)
            End If



            'Start Cam
            'If camwindow.WCFeed.IsCapturing = True Then
            '    camwindow.WCFeed.StopCapture()
            'End If



            'Try
            '    WCFeed.StartCapture(Cams(GEmvoy.Setts.CamNumber))
            '    _db.echo("Cam " & GEmvoy.Setts.CamNumber & " being watched")
            'Catch ex As Exception
            '    _db.echo("ERROR: Error starting Cam. Closing worker thread.")
            '    _db.echo(ex.Message, True)
            '    _db.echo(ex.StackTrace, True)
            '    Return
            '    'e.Cancel = True
            'End Try

            'Dim attempts As Integer = 0
            'While WCFeed.IsCapturing = False
            '    _db.echo("Waiting for cam to start after attempt " & attempts)
            '    Threading.Thread.Sleep(500)
            '    attempts += 1
            '    If attempts = 20 Then
            '        _db.echo("Cam not started after 10 seconds. Timed out. Exiting routine.")
            '        Return
            '    End If
            'End While

            'Start Tickers
            Dim MinuteTimer As Stopwatch = Stopwatch.StartNew()

            If GEmvoy.Setts.CamMode = "Continuous" Then
                _db.echo("Camsnap in continuous mode...")

                While MinuteTimer.Elapsed.TotalMinutes < MinuteLimit
                    If Unlimited = True Then
                        MinuteLimit = MinuteTimer.Elapsed.TotalMinutes + 2
                        '_db.echo("Minutes limit infinite. Increased to: " & MinuteLimit)
                    End If
                    Threading.Thread.Sleep(Millitimer)
                    If (CInt(Math.Ceiling(Rnd() * 100)) + 1) <= SnapProb Then
                        _db.echo(MinuteTimer.Elapsed.TotalMilliseconds & ": Hit - SNAP!")
                        '  _db.echo("Cam running: " & WCFeed.IsCapturing)
                        Try
                            ConvertedImage(WCFeed.GetCurrentImage(), Bright / 100, Contrast / 100, Gamma / 100,
                                           Red / 100, Green / 100, Blue / 100, Timestamp,
                                           (PIP And Not DisablePIP)).Save(FinalFolder & "\" & DateTime.Now.ToString("HH-mm-ss-fff") & ".png",
                                            Imaging.ImageFormat.Png)
                        Catch ex As Exception
                            _db.echo(ex.Message, True)
                            _db.echo(ex.StackTrace, True)
                        End Try
                    Else
                        _db.echo(MinuteTimer.Elapsed.TotalMilliseconds & ": Miss.")
                    End If

                    If (CamSnap.CancellationPending = True) Then
                        e.Cancel = True
                        Exit While
                    End If

                End While

            ElseIf GEmvoy.Setts.CamMode = "Burst" Then
                _db.echo("Camsnap in Burst mode...")
                Dim count As Integer = 0

                While MinuteTimer.Elapsed.TotalMinutes < MinuteLimit

                    If Unlimited = True Then
                        MinuteLimit = MinuteTimer.Elapsed.TotalMinutes + 2
                    End If

                    For count = 0 To BurstNumber
                        Threading.Thread.Sleep(Millitimer)
                        If (CInt(Math.Ceiling(Rnd() * 100)) + 1) <= SnapProb Then
                            _db.echo(MinuteTimer.Elapsed.TotalMilliseconds & ": Hit - SNAP!")
                            '  _db.echo("Cam running: " & WCFeed.IsCapturing)
                            Try
                                ConvertedImage(WCFeed.GetCurrentImage(), Bright / 100, Contrast / 100, Gamma / 100,
                                               Red / 100, Green / 100, Blue / 100, Timestamp,
                                               (PIP And Not DisablePIP)).Save(FinalFolder & "\" & DateTime.Now.ToString("HH-mm-ss-fff") & ".png",
                                                Imaging.ImageFormat.Png)
                            Catch ex As Exception
                                _db.echo(ex.Message, True)
                                _db.echo(ex.StackTrace, True)
                            End Try
                        Else
                            _db.echo(MinuteTimer.Elapsed.TotalMilliseconds & ": Miss.")
                        End If
                    Next

                    Threading.Thread.Sleep(BurstWait * 1000)

                    If (CamSnap.CancellationPending = True) Then
                        e.Cancel = True
                        Exit While
                    End If

                End While
            End If


            _db.echo("Timeout reached or Emu quit. Capture stopping.")
            WCFeed.StopCapture()
            e.Cancel = True
        Catch ex As Exception
            _db.echo(ex.Message, True)
            _db.echo(ex.StackTrace, True)
        End Try
    End Sub

    Public Function ConvertedImage(originalimage As Bitmap, brightness As Single,
                                        contrast As Single, gamma As Single,
                                        red As Single, green As Single, blue As Single,
                                        timestamp As Boolean, pip As Boolean) As Bitmap

        Dim adjustedBrightness As Single = brightness - 1.0F
        Dim adjustedImage As Bitmap = originalimage
        ' create matrix that will brighten and contrast the image
        ' scale red
        ' scale green
        ' scale blue
        ' don't scale alpha
        Dim ptsArray As Single()() = {New Single() {contrast + red, 0, 0, 0, 0}, New Single() {0, contrast + green, 0, 0, 0}, New Single() {0, 0, contrast + blue, 0, 0}, New Single() {0, 0, 0, 1.0F, 0}, New Single() {adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1}}

        Dim ImageAttributes As New ImageAttributes()
        ImageAttributes.ClearColorMatrix()
        ImageAttributes.SetColorMatrix(New ColorMatrix(ptsArray), ColorMatrixFlag.[Default], ColorAdjustType.Bitmap)
        ImageAttributes.SetGamma(gamma, ColorAdjustType.Bitmap)
        Dim g As Graphics = Graphics.FromImage(adjustedImage)
        g.DrawImage(originalimage, New Rectangle(0, 0, adjustedImage.Width, adjustedImage.Height), 0, 0, originalimage.Width, originalimage.Height, _
            GraphicsUnit.Pixel, ImageAttributes)

        'Timestamp
        If timestamp = True Then
            Dim font As Font
            Dim point As PointF
            font = New Font("Arial", 20.0F)
            point = New PointF(5, adjustedImage.Height - 30)
            g.DrawString(String.Format("{0:dd/MM/yyyy}", DateTime.Now), font, Brushes.Yellow, point)
        End If

        'Screenie
        If pip = True Then
            Dim pointx As Integer = adjustedImage.Width * 60 / 100
            Dim pointy As Integer = adjustedImage.Height * 60 / 100
            Dim pipw As Integer = adjustedImage.Width - pointx - 10
            Dim piph As Integer = adjustedImage.Height - pointy - 10
            g.DrawImage(TakeScreenShot,
                        pointx,
                        pointy,
                        pipw,
                        piph)
        End If

        Return adjustedImage
    End Function

    Private Function TakeScreenShot() As Bitmap

        Dim screenSize As Size = New Size(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)

        Dim screenGrab As New Bitmap(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)

        Dim g As Graphics = Graphics.FromImage(screenGrab)

        g.CopyFromScreen(New Point(0, 0), New Point(0, 0), screenSize)

        Return screenGrab

    End Function

#End Region

End Class


